blob: 754b1a1b6ef07181f40d476867bff90fb3b20c58 [file] [log] [blame]
Darin Petkov33af05c2012-02-28 10:10:30 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/vpn_provider.h"
6
Paul Stewart65512e12012-03-26 18:01:08 -07007#include <algorithm>
8
Paul Stewart66815332012-04-09 18:09:36 -07009#include <base/string_util.h>
Darin Petkov33af05c2012-02-28 10:10:30 +010010#include <chromeos/dbus/service_constants.h>
11
12#include "shill/error.h"
Darin Petkov9d1bbe72012-04-25 10:58:59 +020013#include "shill/l2tp_ipsec_driver.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070014#include "shill/logging.h"
Paul Stewartca6abd42012-03-01 15:45:29 -080015#include "shill/manager.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010016#include "shill/openvpn_driver.h"
Paul Stewart66815332012-04-09 18:09:36 -070017#include "shill/profile.h"
18#include "shill/store_interface.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010019#include "shill/vpn_service.h"
20
Paul Stewart66815332012-04-09 18:09:36 -070021using std::set;
Darin Petkov33af05c2012-02-28 10:10:30 +010022using std::string;
Paul Stewartca6abd42012-03-01 15:45:29 -080023using std::vector;
Darin Petkov33af05c2012-02-28 10:10:30 +010024
25namespace shill {
26
27VPNProvider::VPNProvider(ControlInterface *control_interface,
28 EventDispatcher *dispatcher,
29 Metrics *metrics,
30 Manager *manager)
31 : control_interface_(control_interface),
32 dispatcher_(dispatcher),
33 metrics_(metrics),
34 manager_(manager) {}
35
36VPNProvider::~VPNProvider() {}
37
38void VPNProvider::Start() {}
39
40void VPNProvider::Stop() {}
41
42VPNServiceRefPtr VPNProvider::GetService(const KeyValueStore &args,
43 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070044 SLOG(VPN, 2) << __func__;
Darin Petkov7f060332012-03-14 11:46:47 +010045 string type = args.LookupString(flimflam::kProviderTypeProperty, "");
46 if (type.empty()) {
Darin Petkov33af05c2012-02-28 10:10:30 +010047 Error::PopulateAndLog(
48 error, Error::kNotSupported, "Missing VPN type property.");
49 return NULL;
50 }
Paul Stewartca6abd42012-03-01 15:45:29 -080051
Darin Petkov02867712012-03-12 14:25:05 +010052 string storage_id = VPNService::CreateStorageIdentifier(args, error);
53 if (storage_id.empty()) {
54 return NULL;
55 }
56
Paul Stewart39964fa2012-04-04 09:50:25 -070057 // Find a service in the provider list which matches these parameters.
Paul Stewart66815332012-04-09 18:09:36 -070058 VPNServiceRefPtr service = FindService(type, storage_id);
Paul Stewart451aa7f2012-04-11 19:07:58 -070059
Paul Stewart66815332012-04-09 18:09:36 -070060 if (service == NULL) {
Paul Stewart451aa7f2012-04-11 19:07:58 -070061 // Create a service, using the name and type arguments passed in.
62 string name = args.LookupString(flimflam::kProviderNameProperty, "");
63 if (name.empty()) {
64 name = args.LookupString(flimflam::kNameProperty, "");
65 }
66 service = CreateService(type, name, storage_id, error);
67 }
68
Darin Petkov79d74c92012-03-07 17:20:32 +010069 return service;
Paul Stewartca6abd42012-03-01 15:45:29 -080070}
71
72bool VPNProvider::OnDeviceInfoAvailable(const string &link_name,
73 int interface_index) {
74 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
75 it != services_.end();
76 ++it) {
77 if ((*it)->driver()->ClaimInterface(link_name, interface_index)) {
78 return true;
79 }
80 }
81
82 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +010083}
84
Paul Stewart65512e12012-03-26 18:01:08 -070085void VPNProvider::RemoveService(VPNServiceRefPtr service) {
86 vector<VPNServiceRefPtr>::iterator it;
87 it = std::find(services_.begin(), services_.end(), service);
88 if (it != services_.end()) {
89 services_.erase(it);
90 }
91}
92
Paul Stewart66815332012-04-09 18:09:36 -070093void VPNProvider::CreateServicesFromProfile(ProfileRefPtr profile) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070094 SLOG(VPN, 2) << __func__;
Paul Stewart66815332012-04-09 18:09:36 -070095 const StoreInterface *storage = profile->GetConstStorage();
96 set<string> groups =
97 storage->GetGroupsWithKey(flimflam::kProviderTypeProperty);
98 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
99 if (!StartsWithASCII(*it, "vpn_", false)) {
100 continue;
101 }
102
103 string type;
104 if (!storage->GetString(*it, flimflam::kProviderTypeProperty, &type)) {
105 LOG(ERROR) << "Group " << *it << " is missing the "
106 << flimflam::kProviderTypeProperty << " property.";
107 continue;
108 }
109
Paul Stewart451aa7f2012-04-11 19:07:58 -0700110 string name;
111 if (!storage->GetString(*it, flimflam::kProviderNameProperty, &name) &&
112 !storage->GetString(*it, flimflam::kNameProperty, &name)) {
113 LOG(ERROR) << "Group " << *it << " is missing the "
114 << flimflam::kProviderNameProperty << " property.";
115 continue;
116 }
117
Paul Stewart66815332012-04-09 18:09:36 -0700118 VPNServiceRefPtr service = FindService(type, *it);
119 if (service != NULL) {
120 // If the service already exists, it does not need to be configured,
121 // since PushProfile would have already called ConfigureService on it.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700122 SLOG(VPN, 2) << "Service already exists " << *it;
Paul Stewart66815332012-04-09 18:09:36 -0700123 continue;
124 }
125
Paul Stewart66815332012-04-09 18:09:36 -0700126 Error error;
Paul Stewart451aa7f2012-04-11 19:07:58 -0700127 service = CreateService(type, name, *it, &error);
Paul Stewart66815332012-04-09 18:09:36 -0700128
129 if (service == NULL) {
130 LOG(ERROR) << "Could not create service for " << *it;
131 continue;
132 }
133
134 if (!profile->ConfigureService(service)) {
135 LOG(ERROR) << "Could not configure service for " << *it;
136 continue;
137 }
138 }
139}
140
141VPNServiceRefPtr VPNProvider::CreateService(const string &type,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700142 const string &name,
Paul Stewart66815332012-04-09 18:09:36 -0700143 const string &storage_id,
Paul Stewart66815332012-04-09 18:09:36 -0700144 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700145 SLOG(VPN, 2) << __func__ << " type " << type << " name " << name
146 << " storage id " << storage_id;
Paul Stewart66815332012-04-09 18:09:36 -0700147 scoped_ptr<VPNDriver> driver;
148 if (type == flimflam::kProviderOpenVpn) {
149 driver.reset(new OpenVPNDriver(
150 control_interface_, dispatcher_, metrics_, manager_,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700151 manager_->device_info(), manager_->glib()));
Darin Petkov9d1bbe72012-04-25 10:58:59 +0200152 } else if (type == flimflam::kProviderL2tpIpsec) {
153 driver.reset(new L2TPIPSecDriver(
154 control_interface_, dispatcher_, metrics_, manager_,
155 manager_->device_info(), manager_->glib()));
Paul Stewart66815332012-04-09 18:09:36 -0700156 } else {
157 Error::PopulateAndLog(
158 error, Error::kNotSupported, "Unsupported VPN type: " + type);
159 return NULL;
160 }
161
162 VPNServiceRefPtr service = new VPNService(
163 control_interface_, dispatcher_, metrics_, manager_, driver.release());
164 service->set_storage_id(storage_id);
165 service->InitDriverPropertyStore();
Paul Stewart66815332012-04-09 18:09:36 -0700166 if (!name.empty()) {
167 service->set_friendly_name(name);
168 }
169 services_.push_back(service);
170 manager_->RegisterService(service);
171
172 return service;
173}
174
175VPNServiceRefPtr VPNProvider::FindService(const std::string &type,
176 const std::string &storage_id) {
177 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
178 it != services_.end();
179 ++it) {
180 if (type == (*it)->driver()->GetProviderType() &&
181 storage_id == (*it)->GetStorageIdentifier()) {
182 return *it;
183 }
184 }
185
186 return NULL;
187}
188
Darin Petkov4cbff5b2013-01-29 16:29:05 +0100189bool VPNProvider::HasActiveService() const {
190 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
191 it != services_.end(); ++it) {
192 if ((*it)->IsConnecting() || (*it)->IsConnected()) {
193 return true;
194 }
195 }
196 return false;
197}
198
Darin Petkov33af05c2012-02-28 10:10:30 +0100199} // namespace shill