disconnecting interfaces properly on bridge destruction
[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 <libbridge.h>
18
19 #include <debug.h>
20 #include <utils/linked_list.h>
21
22 #include "bridge.h"
23
24 typedef struct private_bridge_t private_bridge_t;
25
26 struct private_bridge_t {
27 /** public interface */
28 bridge_t public;
29 /** device name */
30 char *name;
31 /** list of attached interfaces */
32 linked_list_t *ifaces;
33 };
34
35 /**
36 * defined in iface.c
37 */
38 bool iface_control(char *name, bool up);
39
40 /**
41 * Implementation of bridge_t.get_name.
42 */
43 static char* get_name(private_bridge_t *this)
44 {
45 return this->name;
46 }
47
48 /**
49 * Implementation of bridge_t.create_iface_enumerator.
50 */
51 static enumerator_t* create_iface_enumerator(private_bridge_t *this)
52 {
53 return this->ifaces->create_enumerator(this->ifaces);
54 }
55
56 /**
57 * Implementation of bridge_t.disconnect_iface.
58 */
59 static bool disconnect_iface(private_bridge_t *this, iface_t *iface)
60 {
61 enumerator_t *enumerator;
62 iface_t *current = NULL;
63 bool good = FALSE;
64
65 enumerator = this->ifaces->create_enumerator(this->ifaces);
66 while (enumerator->enumerate(enumerator, (void**)&current))
67 {
68 if (current == iface)
69 {
70 if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
71 {
72 DBG1("removing iface '%s' from bridge '%s' in kernel failed: %m",
73 iface->get_hostif(iface), this->name);
74 }
75 else
76 {
77 iface->set_bridge(iface, NULL);
78 this->ifaces->remove_at(this->ifaces, enumerator);
79 good = TRUE;
80 }
81 break;
82 }
83 }
84 if (iface != current)
85 {
86 DBG1("iface '%s' not found on bridge '%s'", iface->get_hostif(iface),
87 this->name);
88 }
89 enumerator->destroy(enumerator);
90 return good;
91 }
92
93 /**
94 * Implementation of bridge_t.connect_iface.
95 */
96 static bool connect_iface(private_bridge_t *this, iface_t *iface)
97 {
98 if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
99 {
100 DBG1("adding iface '%s' to bridge '%s' failed: %m",
101 iface->get_hostif(iface), this->name);
102 return FALSE;
103 }
104 iface->set_bridge(iface, &this->public);
105 this->ifaces->insert_last(this->ifaces, iface);
106 return TRUE;
107 }
108
109 /**
110 * instance counter to (de-)initialize libbridge
111 */
112 static int instances = 0;
113
114 /**
115 * Implementation of bridge_t.destroy.
116 */
117 static void destroy(private_bridge_t *this)
118 {
119 enumerator_t *enumerator;
120 iface_t *iface;
121
122 enumerator = this->ifaces->create_enumerator(this->ifaces);
123 while (enumerator->enumerate(enumerator, (void**)&iface))
124 {
125 if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
126 {
127 DBG1("disconnecting iface '%s' failed: %m", iface->get_hostif(iface));
128 }
129 iface->set_bridge(iface, NULL);
130 }
131 enumerator->destroy(enumerator);
132 this->ifaces->destroy(this->ifaces);
133 iface_control(this->name, FALSE);
134 if (br_del_bridge(this->name) != 0)
135 {
136 DBG1("deleting bridge '%s' from kernel failed: %m", this->name);
137 }
138 free(this->name);
139 free(this);
140 if (--instances == 0)
141 {
142 br_shutdown();
143 }
144 }
145
146 /**
147 * create the bridge instance
148 */
149 bridge_t *bridge_create(char *name)
150 {
151 private_bridge_t *this;
152
153 if (instances == 0)
154 {
155 if (br_init() != 0)
156 {
157 DBG1("libbridge initialization failed: %m");
158 return NULL;
159 }
160 }
161
162 this = malloc_thing(private_bridge_t);
163 this->public.get_name = (char*(*)(bridge_t*))get_name;
164 this->public.create_iface_enumerator = (enumerator_t*(*)(bridge_t*))create_iface_enumerator;
165 this->public.disconnect_iface = (bool(*)(bridge_t*, iface_t *iface))disconnect_iface;
166 this->public.connect_iface = (bool(*)(bridge_t*, iface_t *iface))connect_iface;
167 this->public.destroy = (void*)destroy;
168
169 if (br_add_bridge(name) != 0)
170 {
171 DBG1("creating bridge '%s' failed: %m", name);
172 free(this);
173 return NULL;
174 }
175 if (!iface_control(name, TRUE))
176 {
177 DBG1("bringing bridge '%s' up failed: %m", name);
178 }
179
180 this->name = strdup(name);
181 this->ifaces = linked_list_create();
182
183 instances++;
184 return &this->public;
185 }
186