blob: 0e2474b3af632093d34815906afdef3c2cade7a7 [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
Paul Stewart0e51ad92013-07-26 14:42:55 -070042ServiceRefPtr 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 Petkov9c6e9812013-03-26 13:49:07 +010052 string host = args.LookupString(flimflam::kProviderHostProperty, "");
53 if (host.empty()) {
54 Error::PopulateAndLog(
55 error, Error::kNotSupported, "Missing VPN host property.");
56 return NULL;
57 }
58
Darin Petkov02867712012-03-12 14:25:05 +010059 string storage_id = VPNService::CreateStorageIdentifier(args, error);
60 if (storage_id.empty()) {
61 return NULL;
62 }
63
Darin Petkov4e02ba22013-04-02 13:44:08 +020064 string name = args.LookupString(flimflam::kNameProperty, "");
Paul Stewart451aa7f2012-04-11 19:07:58 -070065
Darin Petkov9c6e9812013-03-26 13:49:07 +010066 // Find a service in the provider list which matches these parameters.
67 VPNServiceRefPtr service = FindService(type, name, host);
68 if (service == NULL) {
69 service = CreateService(type, name, storage_id, error);
70 }
Darin Petkov79d74c92012-03-07 17:20:32 +010071 return service;
Paul Stewartca6abd42012-03-01 15:45:29 -080072}
73
74bool VPNProvider::OnDeviceInfoAvailable(const string &link_name,
75 int interface_index) {
76 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
77 it != services_.end();
78 ++it) {
79 if ((*it)->driver()->ClaimInterface(link_name, interface_index)) {
80 return true;
81 }
82 }
83
84 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +010085}
86
Paul Stewart65512e12012-03-26 18:01:08 -070087void VPNProvider::RemoveService(VPNServiceRefPtr service) {
88 vector<VPNServiceRefPtr>::iterator it;
89 it = std::find(services_.begin(), services_.end(), service);
90 if (it != services_.end()) {
91 services_.erase(it);
92 }
93}
94
Paul Stewart0e51ad92013-07-26 14:42:55 -070095void VPNProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070096 SLOG(VPN, 2) << __func__;
Paul Stewart66815332012-04-09 18:09:36 -070097 const StoreInterface *storage = profile->GetConstStorage();
98 set<string> groups =
99 storage->GetGroupsWithKey(flimflam::kProviderTypeProperty);
100 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
101 if (!StartsWithASCII(*it, "vpn_", false)) {
102 continue;
103 }
104
105 string type;
106 if (!storage->GetString(*it, flimflam::kProviderTypeProperty, &type)) {
107 LOG(ERROR) << "Group " << *it << " is missing the "
108 << flimflam::kProviderTypeProperty << " property.";
109 continue;
110 }
111
Paul Stewart451aa7f2012-04-11 19:07:58 -0700112 string name;
Darin Petkov4e02ba22013-04-02 13:44:08 +0200113 if (!storage->GetString(*it, flimflam::kNameProperty, &name)) {
Paul Stewart451aa7f2012-04-11 19:07:58 -0700114 LOG(ERROR) << "Group " << *it << " is missing the "
Darin Petkov4e02ba22013-04-02 13:44:08 +0200115 << flimflam::kNameProperty << " property.";
Paul Stewart451aa7f2012-04-11 19:07:58 -0700116 continue;
117 }
118
Darin Petkov9c6e9812013-03-26 13:49:07 +0100119 string host;
120 if (!storage->GetString(*it, flimflam::kProviderHostProperty, &host)) {
121 LOG(ERROR) << "Group " << *it << " is missing the "
122 << flimflam::kProviderHostProperty << " property.";
123 continue;
124 }
125
126 VPNServiceRefPtr service = FindService(type, name, host);
Paul Stewart66815332012-04-09 18:09:36 -0700127 if (service != NULL) {
128 // If the service already exists, it does not need to be configured,
129 // since PushProfile would have already called ConfigureService on it.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700130 SLOG(VPN, 2) << "Service already exists " << *it;
Paul Stewart66815332012-04-09 18:09:36 -0700131 continue;
132 }
133
Paul Stewart66815332012-04-09 18:09:36 -0700134 Error error;
Paul Stewart451aa7f2012-04-11 19:07:58 -0700135 service = CreateService(type, name, *it, &error);
Paul Stewart66815332012-04-09 18:09:36 -0700136
137 if (service == NULL) {
138 LOG(ERROR) << "Could not create service for " << *it;
139 continue;
140 }
141
142 if (!profile->ConfigureService(service)) {
143 LOG(ERROR) << "Could not configure service for " << *it;
144 continue;
145 }
146 }
147}
148
149VPNServiceRefPtr VPNProvider::CreateService(const string &type,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700150 const string &name,
Paul Stewart66815332012-04-09 18:09:36 -0700151 const string &storage_id,
Paul Stewart66815332012-04-09 18:09:36 -0700152 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700153 SLOG(VPN, 2) << __func__ << " type " << type << " name " << name
154 << " storage id " << storage_id;
Darin Petkovc3505a52013-03-18 15:13:29 +0100155#if defined(DISABLE_VPN)
156
157 Error::PopulateAndLog(error, Error::kNotSupported, "VPN is not supported.");
158 return NULL;
159
160#else
161
Paul Stewart66815332012-04-09 18:09:36 -0700162 scoped_ptr<VPNDriver> driver;
163 if (type == flimflam::kProviderOpenVpn) {
164 driver.reset(new OpenVPNDriver(
165 control_interface_, dispatcher_, metrics_, manager_,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700166 manager_->device_info(), manager_->glib()));
Darin Petkov9d1bbe72012-04-25 10:58:59 +0200167 } else if (type == flimflam::kProviderL2tpIpsec) {
168 driver.reset(new L2TPIPSecDriver(
169 control_interface_, dispatcher_, metrics_, manager_,
170 manager_->device_info(), manager_->glib()));
Paul Stewart66815332012-04-09 18:09:36 -0700171 } else {
172 Error::PopulateAndLog(
173 error, Error::kNotSupported, "Unsupported VPN type: " + type);
174 return NULL;
175 }
176
177 VPNServiceRefPtr service = new VPNService(
178 control_interface_, dispatcher_, metrics_, manager_, driver.release());
179 service->set_storage_id(storage_id);
180 service->InitDriverPropertyStore();
Paul Stewart66815332012-04-09 18:09:36 -0700181 if (!name.empty()) {
182 service->set_friendly_name(name);
183 }
184 services_.push_back(service);
185 manager_->RegisterService(service);
186
187 return service;
Darin Petkovc3505a52013-03-18 15:13:29 +0100188
189#endif // DISABLE_VPN
Paul Stewart66815332012-04-09 18:09:36 -0700190}
191
Darin Petkov9c6e9812013-03-26 13:49:07 +0100192VPNServiceRefPtr VPNProvider::FindService(const string &type,
193 const string &name,
194 const string &host) {
Paul Stewart66815332012-04-09 18:09:36 -0700195 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
196 it != services_.end();
197 ++it) {
198 if (type == (*it)->driver()->GetProviderType() &&
Darin Petkov9c6e9812013-03-26 13:49:07 +0100199 name == (*it)->friendly_name() &&
200 host == (*it)->driver()->GetHost()) {
Paul Stewart66815332012-04-09 18:09:36 -0700201 return *it;
202 }
203 }
Paul Stewart66815332012-04-09 18:09:36 -0700204 return NULL;
205}
206
Darin Petkov4cbff5b2013-01-29 16:29:05 +0100207bool VPNProvider::HasActiveService() const {
208 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
209 it != services_.end(); ++it) {
210 if ((*it)->IsConnecting() || (*it)->IsConnected()) {
211 return true;
212 }
213 }
214 return false;
215}
216
Darin Petkov33af05c2012-02-28 10:10:30 +0100217} // namespace shill