child-delete: Reply as usual when concurrently rekeying the IKE_SA
[strongswan.git] / src / dumm / bridge.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <libbridge.h>
19
20 #include <utils/debug.h>
21 #include <collections/linked_list.h>
22
23 #include "bridge.h"
24
25 typedef struct private_bridge_t private_bridge_t;
26
27 struct private_bridge_t {
28 /** public interface */
29 bridge_t public;
30 /** device name */
31 char *name;
32 /** list of attached interfaces */
33 linked_list_t *ifaces;
34 };
35
36 /**
37 * defined in iface.c
38 */
39 bool iface_control(char *name, bool up);
40
41 METHOD(bridge_t, get_name, char*,
42 private_bridge_t *this)
43 {
44 return this->name;
45 }
46
47 METHOD(bridge_t, create_iface_enumerator, enumerator_t*,
48 private_bridge_t *this)
49 {
50 return this->ifaces->create_enumerator(this->ifaces);
51 }
52
53 METHOD(bridge_t, disconnect_iface, bool,
54 private_bridge_t *this, iface_t *iface)
55 {
56 enumerator_t *enumerator;
57 iface_t *current = NULL;
58 bool good = FALSE;
59
60 enumerator = this->ifaces->create_enumerator(this->ifaces);
61 while (enumerator->enumerate(enumerator, (void**)&current))
62 {
63 if (current == iface)
64 {
65 if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
66 {
67 DBG1(DBG_LIB, "removing iface '%s' from bridge '%s' in kernel"
68 " failed: %m", iface->get_hostif(iface), this->name);
69 }
70 else
71 {
72 iface->set_bridge(iface, NULL);
73 this->ifaces->remove_at(this->ifaces, enumerator);
74 good = TRUE;
75 }
76 break;
77 }
78 }
79 if (iface != current)
80 {
81 DBG1(DBG_LIB, "iface '%s' not found on bridge '%s'",
82 iface->get_hostif(iface), this->name);
83 }
84 enumerator->destroy(enumerator);
85 return good;
86 }
87
88 METHOD(bridge_t, connect_iface, bool,
89 private_bridge_t *this, iface_t *iface)
90 {
91 if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
92 {
93 DBG1(DBG_LIB, "adding iface '%s' to bridge '%s' failed: %m",
94 iface->get_hostif(iface), this->name);
95 return FALSE;
96 }
97 iface->set_bridge(iface, &this->public);
98 this->ifaces->insert_last(this->ifaces, iface);
99 return TRUE;
100 }
101
102 /**
103 * instance counter to (de-)initialize libbridge
104 */
105 static int instances = 0;
106
107 METHOD(bridge_t, destroy, void,
108 private_bridge_t *this)
109 {
110 enumerator_t *enumerator;
111 iface_t *iface;
112
113 enumerator = this->ifaces->create_enumerator(this->ifaces);
114 while (enumerator->enumerate(enumerator, (void**)&iface))
115 {
116 if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
117 {
118 DBG1(DBG_LIB, "disconnecting iface '%s' failed: %m",
119 iface->get_hostif(iface));
120 }
121 iface->set_bridge(iface, NULL);
122 }
123 enumerator->destroy(enumerator);
124 this->ifaces->destroy(this->ifaces);
125 iface_control(this->name, FALSE);
126 if (br_del_bridge(this->name) != 0)
127 {
128 DBG1(DBG_LIB, "deleting bridge '%s' from kernel failed: %m",
129 this->name);
130 }
131 free(this->name);
132 free(this);
133 if (--instances == 0)
134 {
135 br_shutdown();
136 }
137 }
138
139 /**
140 * create the bridge instance
141 */
142 bridge_t *bridge_create(char *name)
143 {
144 private_bridge_t *this;
145
146 if (instances == 0)
147 {
148 if (br_init() != 0)
149 {
150 DBG1(DBG_LIB, "libbridge initialization failed: %m");
151 return NULL;
152 }
153 }
154
155 INIT(this,
156 .public = {
157 .get_name = _get_name,
158 .create_iface_enumerator = _create_iface_enumerator,
159 .disconnect_iface = _disconnect_iface,
160 .connect_iface = _connect_iface,
161 .destroy = _destroy,
162 }
163 );
164
165 if (br_add_bridge(name) != 0)
166 {
167 DBG1(DBG_LIB, "creating bridge '%s' failed: %m", name);
168 free(this);
169 return NULL;
170 }
171 if (!iface_control(name, TRUE))
172 {
173 DBG1(DBG_LIB, "bringing bridge '%s' up failed: %m", name);
174 }
175
176 this->name = strdup(name);
177 this->ifaces = linked_list_create();
178
179 instances++;
180 return &this->public;
181 }