xref: /openbmc/phosphor-ipmi-flash/bmc/firmware-handler/net_handler.cpp (revision b487eb47e566df7679e740559582f6d25597feba)
1ded66d0fSJason Ling /*
2ded66d0fSJason Ling  * Copyright 2019 Google Inc.
3ded66d0fSJason Ling  *
4ded66d0fSJason Ling  * Licensed under the Apache License, Version 2.0 (the "License");
5ded66d0fSJason Ling  * you may not use this file except in compliance with the License.
6ded66d0fSJason Ling  * You may obtain a copy of the License at
7ded66d0fSJason Ling  *
8ded66d0fSJason Ling  *     http://www.apache.org/licenses/LICENSE-2.0
9ded66d0fSJason Ling  *
10ded66d0fSJason Ling  * Unless required by applicable law or agreed to in writing, software
11ded66d0fSJason Ling  * distributed under the License is distributed on an "AS IS" BASIS,
12ded66d0fSJason Ling  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ded66d0fSJason Ling  * See the License for the specific language governing permissions and
14ded66d0fSJason Ling  * limitations under the License.
15ded66d0fSJason Ling  */
16ded66d0fSJason Ling 
17ded66d0fSJason Ling #include "net_handler.hpp"
18ded66d0fSJason Ling 
19ded66d0fSJason Ling #include <errno.h>
20ded66d0fSJason Ling #include <netinet/in.h>
21ded66d0fSJason Ling #include <poll.h>
22ded66d0fSJason Ling #include <sys/socket.h>
23ded66d0fSJason Ling #include <unistd.h>
24ded66d0fSJason Ling 
25ded66d0fSJason Ling #include <cstdio>
26ded66d0fSJason Ling 
27ded66d0fSJason Ling namespace ipmi_flash
28ded66d0fSJason Ling {
29ded66d0fSJason Ling 
open()30ded66d0fSJason Ling bool NetDataHandler::open()
31ded66d0fSJason Ling {
32ded66d0fSJason Ling     listenFd.reset(::socket(AF_INET6, SOCK_STREAM, 0));
33ded66d0fSJason Ling     if (*listenFd < 0)
34ded66d0fSJason Ling     {
35ded66d0fSJason Ling         std::perror("Failed to create socket");
36ded66d0fSJason Ling         (void)listenFd.release();
37ded66d0fSJason Ling         return false;
38ded66d0fSJason Ling     }
39ded66d0fSJason Ling 
40ded66d0fSJason Ling     struct sockaddr_in6 listenAddr;
41ded66d0fSJason Ling     listenAddr.sin6_family = AF_INET6;
42ded66d0fSJason Ling     listenAddr.sin6_port = htons(listenPort);
43ded66d0fSJason Ling     listenAddr.sin6_flowinfo = 0;
44ded66d0fSJason Ling     listenAddr.sin6_addr = in6addr_any;
45ded66d0fSJason Ling     listenAddr.sin6_scope_id = 0;
46ded66d0fSJason Ling 
47ded66d0fSJason Ling     if (::bind(*listenFd, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) <
48ded66d0fSJason Ling         0)
49ded66d0fSJason Ling     {
50ded66d0fSJason Ling         std::perror("Failed to bind");
51ded66d0fSJason Ling         return false;
52ded66d0fSJason Ling     }
53ded66d0fSJason Ling 
54ded66d0fSJason Ling     if (::listen(*listenFd, 1) < 0)
55ded66d0fSJason Ling     {
56ded66d0fSJason Ling         std::perror("Failed to listen");
57ded66d0fSJason Ling         return false;
58ded66d0fSJason Ling     }
59ded66d0fSJason Ling     return true;
60ded66d0fSJason Ling }
61ded66d0fSJason Ling 
close()62ded66d0fSJason Ling bool NetDataHandler::close()
63ded66d0fSJason Ling {
64ded66d0fSJason Ling     connFd.reset();
65ded66d0fSJason Ling     listenFd.reset();
66ded66d0fSJason Ling 
67ded66d0fSJason Ling     return true;
68ded66d0fSJason Ling }
69ded66d0fSJason Ling 
copyFrom(std::uint32_t length)70ded66d0fSJason Ling std::vector<std::uint8_t> NetDataHandler::copyFrom(std::uint32_t length)
71ded66d0fSJason Ling {
72ded66d0fSJason Ling     if (!connFd)
73ded66d0fSJason Ling     {
74ded66d0fSJason Ling         struct pollfd fds;
75ded66d0fSJason Ling         fds.fd = *listenFd;
76ded66d0fSJason Ling         fds.events = POLLIN;
77ded66d0fSJason Ling 
78ded66d0fSJason Ling         int ret = ::poll(&fds, 1, timeoutS * 1000);
79ded66d0fSJason Ling         if (ret < 0)
80ded66d0fSJason Ling         {
81ded66d0fSJason Ling             std::perror("Failed to poll");
82ded66d0fSJason Ling             return std::vector<uint8_t>();
83ded66d0fSJason Ling         }
84ded66d0fSJason Ling         else if (ret == 0)
85ded66d0fSJason Ling         {
86ded66d0fSJason Ling             fprintf(stderr, "Timed out waiting for connection\n");
87ded66d0fSJason Ling             return std::vector<uint8_t>();
88ded66d0fSJason Ling         }
89ded66d0fSJason Ling         else if (fds.revents != POLLIN)
90ded66d0fSJason Ling         {
91ded66d0fSJason Ling             fprintf(stderr, "Invalid poll state: 0x%x\n", fds.revents);
92ded66d0fSJason Ling             return std::vector<uint8_t>();
93ded66d0fSJason Ling         }
94ded66d0fSJason Ling 
95ded66d0fSJason Ling         connFd.reset(::accept(*listenFd, nullptr, nullptr));
96ded66d0fSJason Ling         if (*connFd < 0)
97ded66d0fSJason Ling         {
98ded66d0fSJason Ling             std::perror("Failed to accept connection");
99ded66d0fSJason Ling             (void)connFd.release();
100ded66d0fSJason Ling             return std::vector<uint8_t>();
101ded66d0fSJason Ling         }
102ded66d0fSJason Ling 
103ded66d0fSJason Ling         struct timeval tv = {};
104ded66d0fSJason Ling         tv.tv_sec = timeoutS;
105ded66d0fSJason Ling         if (setsockopt(*connFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
106ded66d0fSJason Ling         {
107ded66d0fSJason Ling             std::perror("Failed to set receive timeout");
108ded66d0fSJason Ling             return std::vector<uint8_t>();
109ded66d0fSJason Ling         }
110ded66d0fSJason Ling     }
111ded66d0fSJason Ling 
112ded66d0fSJason Ling     std::vector<std::uint8_t> data(length);
113ded66d0fSJason Ling 
114ded66d0fSJason Ling     std::uint32_t bytesRead = 0;
115ded66d0fSJason Ling     ssize_t ret;
116ded66d0fSJason Ling     do
117ded66d0fSJason Ling     {
118ded66d0fSJason Ling         ret = read(*connFd, data.data() + bytesRead, length - bytesRead);
119ded66d0fSJason Ling         if (ret < 0)
120ded66d0fSJason Ling         {
121ded66d0fSJason Ling             if (errno == EINTR || errno == EAGAIN)
122ded66d0fSJason Ling                 continue;
123ded66d0fSJason Ling             std::perror("Failed to read from socket");
124ded66d0fSJason Ling             break;
125ded66d0fSJason Ling         }
126ded66d0fSJason Ling 
127ded66d0fSJason Ling         bytesRead += ret;
128ded66d0fSJason Ling     } while (ret > 0 && bytesRead < length);
129ded66d0fSJason Ling 
130ded66d0fSJason Ling     if (bytesRead != length)
131ded66d0fSJason Ling     {
132ded66d0fSJason Ling         fprintf(stderr,
133ded66d0fSJason Ling                 "Couldn't read full expected amount. Wanted %u but got %u\n",
134ded66d0fSJason Ling                 length, bytesRead);
135ded66d0fSJason Ling         data.resize(bytesRead);
136ded66d0fSJason Ling     }
137ded66d0fSJason Ling 
138ded66d0fSJason Ling     return data;
139ded66d0fSJason Ling }
140ded66d0fSJason Ling 
writeMeta(const std::vector<std::uint8_t> &)141*b487eb47SWilly Tu bool NetDataHandler::writeMeta(const std::vector<std::uint8_t>&)
142ded66d0fSJason Ling {
143ded66d0fSJason Ling     // TODO: have the host tool send the expected IP address that it will
144ded66d0fSJason Ling     // connect from
145ded66d0fSJason Ling     return true;
146ded66d0fSJason Ling }
147ded66d0fSJason Ling 
readMeta()148ded66d0fSJason Ling std::vector<std::uint8_t> NetDataHandler::readMeta()
149ded66d0fSJason Ling {
150ded66d0fSJason Ling     return std::vector<std::uint8_t>();
151ded66d0fSJason Ling }
152ded66d0fSJason Ling 
153ded66d0fSJason Ling } // namespace ipmi_flash
154