diff options
| author | Benjamin Fair <benjaminfair@google.com> | 2019-10-09 14:18:54 -0700 |
|---|---|---|
| committer | Benjamin Fair <benjaminfair@google.com> | 2019-11-21 15:09:46 -0800 |
| commit | 545f5658305a807dbfe0105a62a8b0cfe42e1808 (patch) | |
| tree | baa0de602a65864b5eac89b34c85076415fae68b /bmc | |
| parent | 1290198fb84fc136ff33cb79f1333fd06977d847 (diff) | |
| download | phosphor-ipmi-flash-545f5658305a807dbfe0105a62a8b0cfe42e1808.tar.gz phosphor-ipmi-flash-545f5658305a807dbfe0105a62a8b0cfe42e1808.zip | |
bmc: add network bridge support
This data handler listens on a TCP port for the image bytes.
Signed-off-by: Benjamin Fair <benjaminfair@google.com>
Change-Id: I388fdd7303c5f8bc93a8f75e97b3abf8adbb81af
Diffstat (limited to 'bmc')
| -rw-r--r-- | bmc/Makefile.am | 4 | ||||
| -rw-r--r-- | bmc/main.cpp | 8 | ||||
| -rw-r--r-- | bmc/net_handler.cpp | 153 | ||||
| -rw-r--r-- | bmc/net_handler.hpp | 45 |
4 files changed, 210 insertions, 0 deletions
diff --git a/bmc/Makefile.am b/bmc/Makefile.am index 0f9b2fb..63c90b4 100644 --- a/bmc/Makefile.am +++ b/bmc/Makefile.am @@ -67,6 +67,10 @@ if ENABLE_NUVOTON_P2A_MBOX libfirmwareblob_common_la_SOURCES += pci_nuvoton_handler.cpp endif +if ENABLE_NET_BRIDGE +libfirmwareblob_common_la_SOURCES += net_handler.cpp +endif + libfirmwareblob_common_la_CXXFLAGS = \ -I$(top_srcdir) \ $(SDBUSPLUS_CFLAGS) \ diff --git a/bmc/main.cpp b/bmc/main.cpp index bc25ff0..0e779b4 100644 --- a/bmc/main.cpp +++ b/bmc/main.cpp @@ -25,6 +25,7 @@ #include "lpc_aspeed.hpp" #include "lpc_handler.hpp" #include "lpc_nuvoton.hpp" +#include "net_handler.hpp" #include "pci_handler.hpp" #include "status.hpp" #include "util.hpp" @@ -71,6 +72,10 @@ LpcDataHandler lpcDataHandler( PciDataHandler pciDataHandler(MAPPED_ADDRESS, memoryRegionSize); #endif +#ifdef ENABLE_NET_BRIDGE +NetDataHandler netDataHandler; +#endif + std::vector<DataHandlerPack> supportedTransports = { {FirmwareFlags::UpdateFlags::ipmi, nullptr}, #ifdef ENABLE_PCI_BRIDGE @@ -79,6 +84,9 @@ std::vector<DataHandlerPack> supportedTransports = { #ifdef ENABLE_LPC_BRIDGE {FirmwareFlags::UpdateFlags::lpc, &lpcDataHandler}, #endif +#ifdef ENABLE_NET_BRIDGE + {FirmwareFlags::UpdateFlags::net, &netDataHandler}, +#endif }; /** diff --git a/bmc/net_handler.cpp b/bmc/net_handler.cpp new file mode 100644 index 0000000..14ae4fb --- /dev/null +++ b/bmc/net_handler.cpp @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "net_handler.hpp" + +#include <errno.h> +#include <netinet/in.h> +#include <poll.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <cstdio> + +namespace ipmi_flash +{ + +bool NetDataHandler::open() +{ + listenFd.reset(::socket(AF_INET6, SOCK_STREAM, 0)); + if (*listenFd < 0) + { + std::perror("Failed to create socket"); + (void)listenFd.release(); + return false; + } + + struct sockaddr_in6 listenAddr; + listenAddr.sin6_family = AF_INET6; + listenAddr.sin6_port = htons(listenPort); + listenAddr.sin6_flowinfo = 0; + listenAddr.sin6_addr = in6addr_any; + listenAddr.sin6_scope_id = 0; + + if (::bind(*listenFd, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < + 0) + { + std::perror("Failed to bind"); + return false; + } + + if (::listen(*listenFd, 1) < 0) + { + std::perror("Failed to listen"); + return false; + } + return true; +} + +bool NetDataHandler::close() +{ + connFd.reset(); + listenFd.reset(); + + return true; +} + +std::vector<std::uint8_t> NetDataHandler::copyFrom(std::uint32_t length) +{ + if (!connFd) + { + struct pollfd fds; + fds.fd = *listenFd; + fds.events = POLLIN; + + int ret = ::poll(&fds, 1, timeoutS * 1000); + if (ret < 0) + { + std::perror("Failed to poll"); + return std::vector<uint8_t>(); + } + else if (ret == 0) + { + fprintf(stderr, "Timed out waiting for connection\n"); + return std::vector<uint8_t>(); + } + else if (fds.revents != POLLIN) + { + fprintf(stderr, "Invalid poll state: 0x%x\n", fds.revents); + return std::vector<uint8_t>(); + } + + connFd.reset(::accept(*listenFd, nullptr, nullptr)); + if (*connFd < 0) + { + std::perror("Failed to accept connection"); + (void)connFd.release(); + return std::vector<uint8_t>(); + } + + struct timeval tv = {}; + tv.tv_sec = timeoutS; + if (setsockopt(*connFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) + { + std::perror("Failed to set receive timeout"); + return std::vector<uint8_t>(); + } + } + + std::vector<std::uint8_t> data(length); + + std::uint32_t bytesRead = 0; + ssize_t ret; + do + { + ret = read(*connFd, data.data() + bytesRead, length - bytesRead); + if (ret < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + std::perror("Failed to read from socket"); + break; + } + + bytesRead += ret; + } while (ret > 0 && bytesRead < length); + + if (bytesRead != length) + { + fprintf(stderr, + "Couldn't read full expected amount. Wanted %u but got %u\n", + length, bytesRead); + data.resize(bytesRead); + } + + return data; +} + +bool NetDataHandler::writeMeta(const std::vector<std::uint8_t>& configuration) +{ + // TODO: have the host tool send the expected IP address that it will + // connect from + return true; +} + +std::vector<std::uint8_t> NetDataHandler::readMeta() +{ + return std::vector<std::uint8_t>(); +} + +} // namespace ipmi_flash diff --git a/bmc/net_handler.hpp b/bmc/net_handler.hpp new file mode 100644 index 0000000..0a0943f --- /dev/null +++ b/bmc/net_handler.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "data_handler.hpp" + +#include <unistd.h> + +#include <cstdint> +#include <optional> +#include <stdplus/handle/managed.hpp> +#include <vector> + +namespace ipmi_flash +{ + +/** + * Data Handler for receiving the image over a network port + */ +class NetDataHandler : public DataInterface +{ + public: + NetDataHandler() : listenFd(std::nullopt), connFd(std::nullopt) + { + } + + bool open() override; + bool close() override; + std::vector<std::uint8_t> copyFrom(std::uint32_t length) override; + bool writeMeta(const std::vector<std::uint8_t>& configuration) override; + std::vector<std::uint8_t> readMeta() override; + + static constexpr std::uint16_t listenPort = 623; + static constexpr int timeoutS = 5; + + private: + static void closefd(int&& fd) + { + ::close(fd); + } + using Fd = stdplus::Managed<int>::Handle<closefd>; + + Fd listenFd; + Fd connFd; +}; + +} // namespace ipmi_flash |

