pppoe_service.cc revision aab63499fccbd5b94fcfd2fa88e5fda83a8b5da8
1// Copyright 2015 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/pppoe/pppoe_service.h"
6
7#include <algorithm>
8#include <map>
9#include <memory>
10#include <string>
11
12#include <base/callback.h>
13#include <base/logging.h>
14#include <chromeos/dbus/service_constants.h>
15
16#include "shill/control_interface.h"
17#include "shill/ethernet/ethernet.h"
18#include "shill/event_dispatcher.h"
19#include "shill/manager.h"
20#include "shill/metrics.h"
21#include "shill/ppp_daemon.h"
22#include "shill/ppp_device.h"
23#include "shill/ppp_device_factory.h"
24#include "shill/store_interface.h"
25
26using base::StringPrintf;
27using std::map;
28using std::string;
29using std::unique_ptr;
30
31namespace shill {
32
33PPPoEService::PPPoEService(ControlInterface *control_interface,
34                           EventDispatcher *dispatcher,
35                           Metrics *metrics,
36                           Manager *manager,
37                           base::WeakPtr<Ethernet> ethernet)
38    : EthernetService(control_interface, dispatcher, metrics, manager,
39                      Technology::kPPPoE, ethernet),
40      control_interface_(control_interface),
41      authenticating_(false),
42      weak_ptr_factory_(this) {
43  PropertyStore *store = this->mutable_store();
44  store->RegisterString(kPPPoEUsernameProperty, &username_);
45  store->RegisterString(kPPPoEPasswordProperty, &password_);
46
47  set_friendly_name("PPPoE");
48  SetConnectable(true);
49  SetAutoConnect(true);
50  NotifyPropertyChanges();
51}
52
53PPPoEService::~PPPoEService() {}
54
55void PPPoEService::Connect(Error *error, const char *reason) {
56  Service::Connect(error, reason);
57
58  CHECK(ethernet());
59
60  if (!ethernet()->link_up()) {
61    Error::PopulateAndLog(
62        FROM_HERE, error, Error::kOperationFailed, StringPrintf(
63            "PPPoE Service %s does not have Ethernet link.",
64            unique_name().c_str()));
65    return;
66  }
67
68  if (IsConnected()) {
69    Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected,
70                          StringPrintf("PPPoE service %s already connected.",
71                                       unique_name().c_str()));
72    return;
73  }
74
75  if (IsConnecting()) {
76    Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
77                          StringPrintf("PPPoE service %s already connecting.",
78                                       unique_name().c_str()));
79    return;
80  }
81
82  PPPDaemon::DeathCallback callback(base::Bind(&PPPoEService::OnPPPDied,
83                                               weak_ptr_factory_.GetWeakPtr()));
84
85  PPPDaemon::Options options;
86  options.no_detach = true;
87  options.no_default_route = true;
88  options.use_peer_dns = true;
89  options.use_pppoe_plugin = true;
90
91  pppd_ = PPPDaemon::Start(
92      control_interface_, manager()->glib(), weak_ptr_factory_.GetWeakPtr(),
93      options, ethernet()->link_name(), callback, error);
94  if (pppd_ == nullptr) {
95    Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError,
96                          StringPrintf("PPPoE service %s can't start pppd.",
97                                       unique_name().c_str()));
98    return;
99  }
100
101  SetState(Service::kStateAssociating);
102}
103
104void PPPoEService::Disconnect(Error *error, const char *reason) {
105  EthernetService::Disconnect(error, reason);
106  if (ppp_device_) {
107    ppp_device_->DropConnection();
108  }
109  ppp_device_ = nullptr;
110  pppd_.reset();
111}
112
113bool PPPoEService::Load(StoreInterface *storage) {
114  if (!Service::Load(storage)) {
115    return false;
116  }
117
118  const string id = GetStorageIdentifier();
119  storage->GetString(id, kPPPoEUsernameProperty, &username_);
120  storage->GetString(id, kPPPoEPasswordProperty, &password_);
121
122  return true;
123}
124
125bool PPPoEService::Save(StoreInterface *storage) {
126  if (!Service::Save(storage)) {
127    return false;
128  }
129
130  const string id = GetStorageIdentifier();
131  storage->SetString(id, kPPPoEUsernameProperty, username_);
132  storage->SetString(id, kPPPoEPasswordProperty, password_);
133
134  return true;
135}
136
137bool PPPoEService::Unload() {
138  username_.clear();
139  password_.clear();
140  return Service::Unload();
141}
142
143void PPPoEService::GetLogin(string *user, string *password) {
144  CHECK(user && password);
145  *user = username_;
146  *password = password_;
147}
148
149void PPPoEService::Notify(const string &reason,
150                          const map<string, string> &dict) {
151  if (reason == kPPPReasonAuthenticating) {
152    OnPPPAuthenticating();
153  } else if (reason == kPPPReasonAuthenticated) {
154    OnPPPAuthenticated();
155  } else if (reason == kPPPReasonConnect) {
156    OnPPPConnected(dict);
157  } else if (reason == kPPPReasonDisconnect) {
158    OnPPPDisconnected();
159  } else {
160    NOTREACHED();
161  }
162}
163
164void PPPoEService::OnPPPDied(pid_t pid, int exit) {
165  OnPPPDisconnected();
166}
167
168void PPPoEService::OnPPPAuthenticating() {
169  authenticating_ = true;
170}
171
172void PPPoEService::OnPPPAuthenticated() {
173  authenticating_ = false;
174}
175
176void PPPoEService::OnPPPConnected(const map<string, string> &params) {
177  const string interface_name = PPPDevice::GetInterfaceName(params);
178
179  DeviceInfo *device_info = manager()->device_info();
180  const int interface_index = device_info->GetIndex(interface_name);
181  if (interface_index < 0) {
182    NOTIMPLEMENTED() << ": No device info for " << interface_name;
183    return;
184  }
185
186  if (ppp_device_) {
187    ppp_device_->SelectService(nullptr);
188  }
189
190  const auto factory = PPPDeviceFactory::GetInstance();
191  ppp_device_ = factory->CreatePPPDevice(
192      control_interface_, dispatcher(), metrics(), manager(), interface_name,
193      interface_index);
194  device_info->RegisterDevice(ppp_device_);
195  ppp_device_->SetEnabled(true);
196  ppp_device_->SelectService(this);
197  ppp_device_->UpdateIPConfigFromPPP(params, false);
198}
199
200void PPPoEService::OnPPPDisconnected() {
201  pppd_.release()->DestroyLater(dispatcher());
202
203  if (authenticating_) {
204    SetFailure(Service::kFailurePPPAuth);
205  } else {
206    SetFailure(Service::kFailureUnknown);
207  }
208
209  Error error;
210  Disconnect(&error, __func__);
211}
212
213}  // namespace shill
214