Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(583)

Side by Side Diff: plugins/vpn.c

Issue 6513009: flimflam: Add L2TP/IPsec VPN plugin (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/flimflam.git@master
Patch Set: Add gateway when requested Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « plugins/vpn.h ('k') | scripts/libppp-plugin.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * 2 *
3 * Connection Manager 3 * Connection Manager
4 * 4 *
5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. 5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 * 10 *
11 * This program is distributed in the hope that it will be useful, 11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * 19 *
20 */ 20 */
21 21
22 /* 22 /*
23 * Support for vpn plugins. Common code to manage a provider object, 23 * Support for vpn plugins. Common code to manage a provider object,
24 * tun device and a task associated with an external vpn process. The 24 * tun device and a task associated with an external vpn process. The
25 * vpn plugin is responsible for launching the external process and 25 * vpn plugin is responsible for launching the external process and
26 * handling notification callbacks to clock the provider state machine. 26 * handling notification callbacks to clock the provider state machine.
27 * 27 *
28 * TODO(sleffler) currently assumes extern vpn service uses tun but not all do
29 * TODO(sleffler) seems to make more sense in src than plugins 28 * TODO(sleffler) seems to make more sense in src than plugins
30 */ 29 */
31 30
32 #ifdef HAVE_CONFIG_H 31 #ifdef HAVE_CONFIG_H
33 #include <config.h> 32 #include <config.h>
34 #endif 33 #endif
35 34
36 #include <string.h> 35 #include <string.h>
37 #include <fcntl.h> 36 #include <fcntl.h>
38 #include <unistd.h> 37 #include <unistd.h>
(...skipping 11 matching lines...) Expand all
50 #include <glib/gprintf.h> 49 #include <glib/gprintf.h>
51 50
52 #include <connman/provider.h> 51 #include <connman/provider.h>
53 #include <connman/log.h> 52 #include <connman/log.h>
54 #include <connman/rtnl.h> 53 #include <connman/rtnl.h>
55 #include <connman/task.h> 54 #include <connman/task.h>
56 #include <connman/inet.h> 55 #include <connman/inet.h>
57 56
58 #include "vpn.h" 57 #include "vpn.h"
59 58
60 #define»_DBG_VPN(fmt, arg...)» DBG(DBG_VPN, fmt, ## arg) 59 #define _DBG_VPN(fmt, arg...) DBG(DBG_VPN, fmt, ## arg)
61 60
62 struct vpn_data { 61 struct vpn_data {
63 struct connman_provider *provider; 62 struct connman_provider *provider;
64 char *if_name; 63 char *if_name;
65 unsigned flags; 64 unsigned flags;
66 unsigned int watch; 65 unsigned int watch;
67 unsigned int state; 66 unsigned int state;
68 struct connman_task *task; 67 struct connman_task *task;
69 }; 68 };
70 69
71 struct vpn_driver_data { 70 struct vpn_driver_data {
72 const char *name; 71 const char *name;
73 const char *program; 72 const char *program;
74 struct vpn_driver *vpn_driver; 73 struct vpn_driver *vpn_driver;
75 struct connman_provider_driver provider_driver; 74 struct connman_provider_driver provider_driver;
76 }; 75 };
77 76
78 static GHashTable *driver_hash = NULL; 77 static GHashTable *driver_hash = NULL;
79 78
80 static int kill_tun(char *tun_name) 79 static int kill_tun(struct connman_provider *provider)
81 { 80 {
81 struct vpn_data *data = connman_provider_get_data(provider);
82 struct vpn_driver_data *vpn_driver_data;
83 const char *name;
82 struct ifreq ifr; 84 struct ifreq ifr;
83 int fd, err; 85 int fd, err;
84 86
87 if (data == NULL)
88 return -1;
89
90 name = connman_provider_get_driver_name(provider);
91 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
92
93 if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver !=NULL &&
94 vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
95 return 0;
96
85 memset(&ifr, 0, sizeof(ifr)); 97 memset(&ifr, 0, sizeof(ifr));
86 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; 98 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
87 » strncpy(ifr.ifr_name, tun_name, sizeof(ifr.ifr_name)); 99 » strncpy(ifr.ifr_name, data->if_name, sizeof(ifr.ifr_name));
88 100
89 fd = open("/dev/net/tun", O_RDWR); 101 fd = open("/dev/net/tun", O_RDWR);
90 if (fd < 0) { 102 if (fd < 0) {
91 err = -errno; 103 err = -errno;
92 connman_error("Failed to open /dev/net/tun to device %s: %s", 104 connman_error("Failed to open /dev/net/tun to device %s: %s",
93 » » » tun_name, strerror(errno)); 105 » » » data->if_name, strerror(errno));
94 return err; 106 return err;
95 } 107 }
96 108
97 if (ioctl(fd, TUNSETIFF, (void *)&ifr)) { 109 if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
98 err = -errno; 110 err = -errno;
99 connman_error("Failed to TUNSETIFF for device %s to it: %s", 111 connman_error("Failed to TUNSETIFF for device %s to it: %s",
100 » » » tun_name, strerror(errno)); 112 » » » data->if_name, strerror(errno));
101 close(fd); 113 close(fd);
102 return err; 114 return err;
103 } 115 }
104 116
105 if (ioctl(fd, TUNSETPERSIST, 0)) { 117 if (ioctl(fd, TUNSETPERSIST, 0)) {
106 err = -errno; 118 err = -errno;
107 connman_error("Failed to set tun device %s nonpersistent: %s", 119 connman_error("Failed to set tun device %s nonpersistent: %s",
108 » » » tun_name, strerror(errno)); 120 » » » data->if_name, strerror(errno));
109 close(fd); 121 close(fd);
110 return err; 122 return err;
111 } 123 }
112 close(fd); 124 close(fd);
113 » _DBG_VPN("Killed tun device %s", tun_name); 125 » _DBG_VPN("Killed tun device %s", data->if_name);
114 return 0; 126 return 0;
115 } 127 }
116 128
117 void vpn_died(struct connman_task *task, void *user_data) 129 void vpn_died(struct connman_task *task, void *user_data)
118 { 130 {
119 struct connman_provider *provider = user_data; 131 struct connman_provider *provider = user_data;
120 struct vpn_data *data = connman_provider_get_data(provider); 132 struct vpn_data *data = connman_provider_get_data(provider);
121 int state = data->state; 133 int state = data->state;
122 134
123 _DBG_VPN("provider %p data %p", provider, data); 135 _DBG_VPN("provider %p data %p", provider, data);
124 136
125 if (!data) 137 if (!data)
126 goto vpn_exit; 138 goto vpn_exit;
127 139
128 » kill_tun(data->if_name); 140 » kill_tun(provider);
129 connman_provider_set_data(provider, NULL); 141 connman_provider_set_data(provider, NULL);
130 connman_rtnl_remove_watch(data->watch); 142 connman_rtnl_remove_watch(data->watch);
131 143
132 vpn_exit: 144 vpn_exit:
133 if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) 145 if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT)
134 connman_provider_set_state(provider, 146 connman_provider_set_state(provider,
135 CONNMAN_PROVIDER_STATE_FAILURE); 147 CONNMAN_PROVIDER_STATE_FAILURE);
136 else 148 else
137 connman_provider_set_state(provider, 149 connman_provider_set_state(provider,
138 CONNMAN_PROVIDER_STATE_IDLE); 150 CONNMAN_PROVIDER_STATE_IDLE);
139 151
140 connman_provider_set_index(provider, -1); 152 connman_provider_set_index(provider, -1);
141 connman_provider_unref(data->provider); 153 connman_provider_unref(data->provider);
142 g_free(data); 154 g_free(data);
143 155
144 connman_task_destroy(task); 156 connman_task_destroy(task);
145 } 157 }
146 158
147 static void vpn_newlink(const char *ifname, unsigned flags, unsigned change,» » » » void *user_data) 159 int vpn_set_ifname(struct connman_provider *provider, const char *ifname)
160 {
161 » struct vpn_data *data = connman_provider_get_data(provider);
162 » int index;
163
164 » if (data == NULL) {
165 » » _DBG_VPN("%s: provider data not accessible", __func__);
166 » » return -EIO;
167 » }
168
169 » if (ifname == NULL) {
170 » » _DBG_VPN("%s: ifname not provided", __func__);
171 » » return -EIO;
172 » }
173
174 » index = connman_inet_ifindex(ifname);
175 » if (index < 0) {
176 » » _DBG_VPN("%s: could not get ifindex from %s", __func__, ifname);
177 » » return -EIO;
178 » }
179
180 » data->if_name = (char *)g_strdup(ifname);
181 » connman_provider_set_index(provider, index);
182
183 » /* Set connect state to retry creating ipconfig with index above. */
184 » connman_provider_set_state(provider, CONNMAN_PROVIDER_STATE_CONNECT);
185
186 » return 0;
187 }
188
189 static void vpn_newlink(const char *ifname, unsigned flags, unsigned change,
190 » » » void *user_data)
148 { 191 {
149 struct connman_provider *provider = user_data; 192 struct connman_provider *provider = user_data;
150 struct vpn_data *data = connman_provider_get_data(provider); 193 struct vpn_data *data = connman_provider_get_data(provider);
151 194
152 if ((data->flags & IFF_UP) != (flags & IFF_UP)) { 195 if ((data->flags & IFF_UP) != (flags & IFF_UP)) {
153 if (flags & IFF_UP) { 196 if (flags & IFF_UP) {
154 data->state = VPN_STATE_READY; 197 data->state = VPN_STATE_READY;
155 connman_provider_set_state(provider, 198 connman_provider_set_state(provider,
156 CONNMAN_PROVIDER_STATE_READY); 199 CONNMAN_PROVIDER_STATE_READY);
157 } 200 }
158 } 201 }
159 data->flags = flags; 202 data->flags = flags;
160 } 203 }
161 204
162 static void vpn_notify(struct connman_task *task, 205 static DBusMessage *vpn_notify(struct connman_task *task,
163 DBusMessage *msg, void *user_data) 206 DBusMessage *msg, void *user_data)
164 { 207 {
165 struct connman_provider *provider = user_data; 208 struct connman_provider *provider = user_data;
166 struct vpn_data *data; 209 struct vpn_data *data;
167 struct vpn_driver_data *vpn_driver_data; 210 struct vpn_driver_data *vpn_driver_data;
168 const char *name; 211 const char *name;
169 int state, index; 212 int state, index;
170 213
171 data = connman_provider_get_data(provider); 214 data = connman_provider_get_data(provider);
172 215
173 name = connman_provider_get_driver_name(provider); 216 name = connman_provider_get_driver_name(provider);
174 vpn_driver_data = g_hash_table_lookup(driver_hash, name); 217 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
175 if (vpn_driver_data == NULL) 218 if (vpn_driver_data == NULL)
176 » » return; 219 » » return NULL;
177 220
178 state = vpn_driver_data->vpn_driver->notify(msg, provider); 221 state = vpn_driver_data->vpn_driver->notify(msg, provider);
179 switch (state) { 222 switch (state) {
180 case VPN_STATE_CONNECT: 223 case VPN_STATE_CONNECT:
181 case VPN_STATE_READY: 224 case VPN_STATE_READY:
182 index = connman_provider_get_index(provider); 225 index = connman_provider_get_index(provider);
183 data->watch = connman_rtnl_add_newlink_watch(index, 226 data->watch = connman_rtnl_add_newlink_watch(index,
184 vpn_newlink, provider); 227 vpn_newlink, provider);
185 connman_inet_ifup(index); 228 connman_inet_ifup(index);
186 break; 229 break;
187 230
188 case VPN_STATE_UNKNOWN: 231 case VPN_STATE_UNKNOWN:
189 case VPN_STATE_IDLE: 232 case VPN_STATE_IDLE:
190 case VPN_STATE_DISCONNECT: 233 case VPN_STATE_DISCONNECT:
191 case VPN_STATE_FAILURE: 234 case VPN_STATE_FAILURE:
192 connman_provider_set_state(provider, 235 connman_provider_set_state(provider,
193 CONNMAN_PROVIDER_STATE_DISCONNECT); 236 CONNMAN_PROVIDER_STATE_DISCONNECT);
194 break; 237 break;
195 } 238 }
239
240 return NULL;
196 } 241 }
197 242
198 static int vpn_connect(struct connman_provider *provider) 243 static int vpn_create_tun(struct connman_provider *provider)
199 { 244 {
200 struct vpn_data *data = connman_provider_get_data(provider); 245 struct vpn_data *data = connman_provider_get_data(provider);
201 struct vpn_driver_data *vpn_driver_data;
202 struct ifreq ifr; 246 struct ifreq ifr;
203 const char *name;
204 int i, fd, index; 247 int i, fd, index;
205 int ret = 0; 248 int ret = 0;
206 249
207 » if (data != NULL) 250 » if (data == NULL) {
208 » » return -EISCONN; 251 » » connman_error("%s: called out of order", __func__);
209 252 » » return -EIO;
210 » data = g_try_new0(struct vpn_data, 1); 253 » }
211 » if (data == NULL)
212 » » return -ENOMEM;
213
214 » data->provider = connman_provider_ref(provider);
215 » data->watch = 0;
216 » data->flags = 0;
217 » data->task = NULL;
218 » data->state = VPN_STATE_IDLE;
219
220 » connman_provider_set_data(provider, data);
221
222 » name = connman_provider_get_driver_name(provider);
223 » vpn_driver_data = g_hash_table_lookup(driver_hash, name);
224 254
225 fd = open("/dev/net/tun", O_RDWR); 255 fd = open("/dev/net/tun", O_RDWR);
226 if (fd < 0) { 256 if (fd < 0) {
227 i = -errno; 257 i = -errno;
228 connman_error("%s: failed to open /dev/net/tun: %s", 258 connman_error("%s: failed to open /dev/net/tun: %s",
229 __func__, strerror(errno)); 259 __func__, strerror(errno));
230 ret = i; 260 ret = i;
231 goto exist_err; 261 goto exist_err;
232 } 262 }
233 263
(...skipping 28 matching lines...) Expand all
262 close(fd); 292 close(fd);
263 ret = i; 293 ret = i;
264 goto exist_err; 294 goto exist_err;
265 } 295 }
266 296
267 close(fd); 297 close(fd);
268 298
269 index = connman_inet_ifindex(data->if_name); 299 index = connman_inet_ifindex(data->if_name);
270 if (index < 0) { 300 if (index < 0) {
271 connman_error("%s: failed to get tun ifindex", __func__); 301 connman_error("%s: failed to get tun ifindex", __func__);
272 » » kill_tun(data->if_name); 302 » » kill_tun(provider);
273 ret = -EIO; 303 ret = -EIO;
274 goto exist_err; 304 goto exist_err;
275 } 305 }
276 connman_provider_set_index(provider, index); 306 connman_provider_set_index(provider, index);
277 307
308 return 0;
309
310 exist_err:
311 return ret;
312 }
313
314 static int vpn_connect(struct connman_provider *provider)
315 {
316 struct vpn_data *data = connman_provider_get_data(provider);
317 struct vpn_driver_data *vpn_driver_data;
318 const char *name;
319 int ret = 0;
320
321 if (data != NULL) {
322 _DBG_VPN("%s: data != NULL", __func__);
323 return -EISCONN;
324 }
325
326 data = g_try_new0(struct vpn_data, 1);
327 if (data == NULL)
328 return -ENOMEM;
329
330 data->provider = connman_provider_ref(provider);
331 data->watch = 0;
332 data->flags = 0;
333 data->task = NULL;
334 data->state = VPN_STATE_IDLE;
335
336 connman_provider_set_data(provider, data);
337
338 name = connman_provider_get_driver_name(provider);
339 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
340
341 if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
342 vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
343
344 ret = vpn_create_tun(provider);
345 if (ret < 0)
346 goto exist_err;
347 }
348
278 data->task = connman_task_create(vpn_driver_data->program); 349 data->task = connman_task_create(vpn_driver_data->program);
279 350
280 if (data->task == NULL) { 351 if (data->task == NULL) {
281 ret = -ENOMEM; 352 ret = -ENOMEM;
282 » » kill_tun(data->if_name); 353 » » kill_tun(provider);
283 goto exist_err; 354 goto exist_err;
284 } 355 }
285 356
286 if (connman_task_set_notify(data->task, "notify", 357 if (connman_task_set_notify(data->task, "notify",
287 vpn_notify, provider)) { 358 vpn_notify, provider)) {
288 ret = -ENOMEM; 359 ret = -ENOMEM;
289 » » kill_tun(data->if_name); 360 » » kill_tun(provider);
290 connman_task_destroy(data->task); 361 connman_task_destroy(data->task);
291 data->task = NULL; 362 data->task = NULL;
292 goto exist_err; 363 goto exist_err;
293 } 364 }
294 365
295 ret = vpn_driver_data->vpn_driver->connect(provider, data->task, 366 ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
296 data->if_name); 367 data->if_name);
297 if (ret < 0) { 368 if (ret < 0) {
298 » » kill_tun(data->if_name); 369 » » kill_tun(provider);
299 connman_task_destroy(data->task); 370 connman_task_destroy(data->task);
300 data->task = NULL; 371 data->task = NULL;
301 goto exist_err; 372 goto exist_err;
302 } 373 }
303 374
304 _DBG_VPN("%s started with dev %s", 375 _DBG_VPN("%s started with dev %s",
305 vpn_driver_data->provider_driver.name, data->if_name); 376 vpn_driver_data->provider_driver.name, data->if_name);
306 377
307 data->state = VPN_STATE_CONNECT; 378 data->state = VPN_STATE_CONNECT;
308 379
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 connman_task_stop(data->task); 419 connman_task_stop(data->task);
349 420
350 return 0; 421 return 0;
351 } 422 }
352 423
353 static int vpn_remove(struct connman_provider *provider) 424 static int vpn_remove(struct connman_provider *provider)
354 { 425 {
355 struct vpn_data *data; 426 struct vpn_data *data;
356 427
357 data = connman_provider_get_data(provider); 428 data = connman_provider_get_data(provider);
358 connman_provider_set_data(provider, NULL);
359 if (data == NULL) 429 if (data == NULL)
360 return 0; 430 return 0;
361 431
362 if (data->watch != 0) 432 if (data->watch != 0)
363 connman_rtnl_remove_watch(data->watch); 433 connman_rtnl_remove_watch(data->watch);
364 data->watch = 0; 434 data->watch = 0;
365 connman_task_stop(data->task); 435 connman_task_stop(data->task);
366 436
367 g_usleep(G_USEC_PER_SEC); 437 g_usleep(G_USEC_PER_SEC);
368 » kill_tun(data->if_name); 438 » kill_tun(provider);
439 » connman_provider_set_data(provider, NULL);
369 return 0; 440 return 0;
370 } 441 }
371 442
372 int vpn_register(const char *name, struct vpn_driver *vpn_driver, 443 int vpn_register(const char *name, struct vpn_driver *vpn_driver,
373 const char *program) 444 const char *program)
374 { 445 {
375 struct vpn_driver_data *data; 446 struct vpn_driver_data *data;
376 447
377 _DBG_VPN("name %s program %s", name, program); 448 _DBG_VPN("name %s program %s", name, program);
378 449
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 if (data == NULL) 483 if (data == NULL)
413 return; 484 return;
414 485
415 connman_provider_driver_unregister(&data->provider_driver); 486 connman_provider_driver_unregister(&data->provider_driver);
416 487
417 g_hash_table_remove(driver_hash, name); 488 g_hash_table_remove(driver_hash, name);
418 489
419 if (g_hash_table_size(driver_hash) == 0) 490 if (g_hash_table_size(driver_hash) == 0)
420 g_hash_table_destroy(driver_hash); 491 g_hash_table_destroy(driver_hash);
421 } 492 }
OLDNEW
« no previous file with comments | « plugins/vpn.h ('k') | scripts/libppp-plugin.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698