1*7ba4dab5SXin Li /*
2*7ba4dab5SXin Li * Copyright (C) 2016 The Android Open Source Project
3*7ba4dab5SXin Li *
4*7ba4dab5SXin Li * Licensed under the Apache License, Version 2.0 (the "License");
5*7ba4dab5SXin Li * you may not use this file except in compliance with the License.
6*7ba4dab5SXin Li * You may obtain a copy of the License at
7*7ba4dab5SXin Li *
8*7ba4dab5SXin Li * http://www.apache.org/licenses/LICENSE-2.0
9*7ba4dab5SXin Li *
10*7ba4dab5SXin Li * Unless required by applicable law or agreed to in writing, software
11*7ba4dab5SXin Li * distributed under the License is distributed on an "AS IS" BASIS,
12*7ba4dab5SXin Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*7ba4dab5SXin Li * See the License for the specific language governing permissions and
14*7ba4dab5SXin Li * limitations under the License.
15*7ba4dab5SXin Li */
16*7ba4dab5SXin Li
17*7ba4dab5SXin Li #include <errno.h>
18*7ba4dab5SXin Li #include <string.h>
19*7ba4dab5SXin Li #include <sys/socket.h>
20*7ba4dab5SXin Li #include <sys/types.h>
21*7ba4dab5SXin Li #include <unistd.h>
22*7ba4dab5SXin Li
23*7ba4dab5SXin Li #include <android-base/logging.h>
24*7ba4dab5SXin Li #include <cutils/sockets.h>
25*7ba4dab5SXin Li
26*7ba4dab5SXin Li #include <nvram/hal/nvram_device_adapter.h>
27*7ba4dab5SXin Li #include <nvram/messages/nvram_messages.h>
28*7ba4dab5SXin Li
29*7ba4dab5SXin Li namespace {
30*7ba4dab5SXin Li
31*7ba4dab5SXin Li constexpr char kFakeNvramControlSocketName[] = "nvram";
32*7ba4dab5SXin Li
33*7ba4dab5SXin Li // This instantiates an |NvramManager| with the storage interface wired up with
34*7ba4dab5SXin Li // an in-memory implementation. This *DOES NOT* meet the persistence and tamper
35*7ba4dab5SXin Li // evidence requirements of the HAL, but is useful for demonstration and running
36*7ba4dab5SXin Li // tests against the |NvramManager| implementation.
37*7ba4dab5SXin Li class TestingNvramImplementation : public nvram::NvramImplementation {
38*7ba4dab5SXin Li public:
39*7ba4dab5SXin Li ~TestingNvramImplementation() override;
40*7ba4dab5SXin Li
41*7ba4dab5SXin Li void Execute(const nvram::Request& request,
42*7ba4dab5SXin Li nvram::Response* response) override;
43*7ba4dab5SXin Li
44*7ba4dab5SXin Li private:
45*7ba4dab5SXin Li // Connects the fake NVRAM control socket it it is not open already. Returns
46*7ba4dab5SXin Li // true if the channel is open, false on errors.
47*7ba4dab5SXin Li bool Connect();
48*7ba4dab5SXin Li
49*7ba4dab5SXin Li // Sends a request to the fake NVRAM daemon. Returns true if successful, false
50*7ba4dab5SXin Li // on any I/O errors.
51*7ba4dab5SXin Li bool SendRequest(const nvram::Request& request, nvram::Response* response);
52*7ba4dab5SXin Li
53*7ba4dab5SXin Li // A file descriptor of the socket connected to the fake NVRAM daemon.
54*7ba4dab5SXin Li int nvram_socket_fd_ = -1;
55*7ba4dab5SXin Li
56*7ba4dab5SXin Li // The command buffer, used for encoding request and decoding responses.
57*7ba4dab5SXin Li uint8_t command_buffer_[4096];
58*7ba4dab5SXin Li };
59*7ba4dab5SXin Li
~TestingNvramImplementation()60*7ba4dab5SXin Li TestingNvramImplementation::~TestingNvramImplementation() {
61*7ba4dab5SXin Li if (nvram_socket_fd_ != -1) {
62*7ba4dab5SXin Li // No need to handle EINTR specially here as bionic filters it out.
63*7ba4dab5SXin Li if (close(nvram_socket_fd_)) {
64*7ba4dab5SXin Li PLOG(ERROR) << "Failed to close NVRAM command socket";
65*7ba4dab5SXin Li }
66*7ba4dab5SXin Li nvram_socket_fd_ = -1;
67*7ba4dab5SXin Li }
68*7ba4dab5SXin Li }
69*7ba4dab5SXin Li
Execute(const nvram::Request & request,nvram::Response * response)70*7ba4dab5SXin Li void TestingNvramImplementation::Execute(const nvram::Request& request,
71*7ba4dab5SXin Li nvram::Response* response) {
72*7ba4dab5SXin Li if (!SendRequest(request, response)) {
73*7ba4dab5SXin Li response->result = NV_RESULT_INTERNAL_ERROR;
74*7ba4dab5SXin Li }
75*7ba4dab5SXin Li }
76*7ba4dab5SXin Li
Connect()77*7ba4dab5SXin Li bool TestingNvramImplementation::Connect() {
78*7ba4dab5SXin Li if (nvram_socket_fd_ != -1) {
79*7ba4dab5SXin Li return true;
80*7ba4dab5SXin Li }
81*7ba4dab5SXin Li
82*7ba4dab5SXin Li int rc =
83*7ba4dab5SXin Li socket_local_client(kFakeNvramControlSocketName,
84*7ba4dab5SXin Li ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
85*7ba4dab5SXin Li if (rc < 0) {
86*7ba4dab5SXin Li PLOG(ERROR) << "Failed to connect fake NVRAM control socket";
87*7ba4dab5SXin Li return false;
88*7ba4dab5SXin Li }
89*7ba4dab5SXin Li
90*7ba4dab5SXin Li nvram_socket_fd_ = rc;
91*7ba4dab5SXin Li return true;
92*7ba4dab5SXin Li }
93*7ba4dab5SXin Li
SendRequest(const nvram::Request & request,nvram::Response * response)94*7ba4dab5SXin Li bool TestingNvramImplementation::SendRequest(const nvram::Request& request,
95*7ba4dab5SXin Li nvram::Response* response) {
96*7ba4dab5SXin Li if (!Connect()) {
97*7ba4dab5SXin Li return false;
98*7ba4dab5SXin Li }
99*7ba4dab5SXin Li
100*7ba4dab5SXin Li size_t request_size = sizeof(command_buffer_);
101*7ba4dab5SXin Li if (!nvram::Encode(request, command_buffer_, &request_size)) {
102*7ba4dab5SXin Li LOG(ERROR) << "Failed to encode NVRAM request.";
103*7ba4dab5SXin Li return false;
104*7ba4dab5SXin Li }
105*7ba4dab5SXin Li
106*7ba4dab5SXin Li ssize_t rc = TEMP_FAILURE_RETRY(
107*7ba4dab5SXin Li write(nvram_socket_fd_, command_buffer_, request_size));
108*7ba4dab5SXin Li if (rc < 0) {
109*7ba4dab5SXin Li PLOG(ERROR) << "Failed to send request on NVRAM control socket";
110*7ba4dab5SXin Li return false;
111*7ba4dab5SXin Li }
112*7ba4dab5SXin Li
113*7ba4dab5SXin Li rc = TEMP_FAILURE_RETRY(
114*7ba4dab5SXin Li read(nvram_socket_fd_, command_buffer_, sizeof(command_buffer_)));
115*7ba4dab5SXin Li if (rc < 0 || static_cast<size_t>(rc) > sizeof(command_buffer_)) {
116*7ba4dab5SXin Li PLOG(ERROR) << "Failed to read NVRAM response";
117*7ba4dab5SXin Li return false;
118*7ba4dab5SXin Li }
119*7ba4dab5SXin Li
120*7ba4dab5SXin Li if (!nvram::Decode(command_buffer_, static_cast<size_t>(rc), response)) {
121*7ba4dab5SXin Li LOG(ERROR) << "Failed to decode NVRAM response.";
122*7ba4dab5SXin Li return false;
123*7ba4dab5SXin Li }
124*7ba4dab5SXin Li
125*7ba4dab5SXin Li return true;
126*7ba4dab5SXin Li }
127*7ba4dab5SXin Li
128*7ba4dab5SXin Li } // namespace
129*7ba4dab5SXin Li
testing_nvram_open(const hw_module_t * module,const char * device_id,hw_device_t ** device_ptr)130*7ba4dab5SXin Li extern "C" int testing_nvram_open(const hw_module_t* module,
131*7ba4dab5SXin Li const char* device_id,
132*7ba4dab5SXin Li hw_device_t** device_ptr) {
133*7ba4dab5SXin Li if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
134*7ba4dab5SXin Li return -EINVAL;
135*7ba4dab5SXin Li }
136*7ba4dab5SXin Li
137*7ba4dab5SXin Li nvram::NvramDeviceAdapter* adapter =
138*7ba4dab5SXin Li new nvram::NvramDeviceAdapter(module, new TestingNvramImplementation);
139*7ba4dab5SXin Li *device_ptr = adapter->as_device();
140*7ba4dab5SXin Li return 0;
141*7ba4dab5SXin Li }
142