blob: 0012746ce56b908150d58529d94b259e8cd65eb1 [file] [log] [blame]
Patrick Venture690a2342020-05-17 11:51:31 -07001#include "transporthandler.hpp"
2
Johnathan Manteyaffadb52019-10-07 10:13:53 -07003#include "app/channel.hpp"
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00004#include "user_channel/cipher_mgmt.hpp"
Johnathan Manteyaffadb52019-10-07 10:13:53 -07005
Patrick Venture0b02be92018-08-31 11:55:55 -07006#include <arpa/inet.h>
William A. Kennington IIIc514d872019-04-06 18:19:38 -07007#include <netinet/ether.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07008
William A. Kennington IIIc514d872019-04-06 18:19:38 -07009#include <array>
10#include <bitset>
11#include <cinttypes>
12#include <cstdint>
13#include <cstring>
Johnathan Manteyaffadb52019-10-07 10:13:53 -070014#include <fstream>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070015#include <functional>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070016#include <ipmid/api.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070017#include <ipmid/message.hpp>
18#include <ipmid/message/types.hpp>
19#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070020#include <ipmid/utils.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070021#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070022#include <phosphor-logging/elog-errors.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070023#include <phosphor-logging/elog.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070024#include <phosphor-logging/log.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070025#include <sdbusplus/bus.hpp>
26#include <sdbusplus/exception.hpp>
tomjose26e17732016-03-03 08:52:51 -060027#include <string>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070028#include <string_view>
29#include <type_traits>
30#include <unordered_map>
31#include <unordered_set>
32#include <user_channel/channel_layer.hpp>
33#include <utility>
34#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070035#include <xyz/openbmc_project/Common/error.hpp>
Johnathan Mantey65265362019-11-14 11:24:19 -080036#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070037#include <xyz/openbmc_project/Network/IP/server.hpp>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070038#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070039
William A. Kennington IIIc514d872019-04-06 18:19:38 -070040using phosphor::logging::commit;
41using phosphor::logging::elog;
42using phosphor::logging::entry;
43using phosphor::logging::level;
44using phosphor::logging::log;
45using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Johnathan Mantey65265362019-11-14 11:24:19 -080046using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070047using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070048using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070049
Johnathan Manteyaffadb52019-10-07 10:13:53 -070050namespace cipher
51{
52
53std::vector<uint8_t> getCipherList()
54{
55 std::vector<uint8_t> cipherList;
56
57 std::ifstream jsonFile(cipher::configFile);
58 if (!jsonFile.is_open())
59 {
60 log<level::ERR>("Channel Cipher suites file not found");
61 elog<InternalFailure>();
62 }
63
64 auto data = Json::parse(jsonFile, nullptr, false);
65 if (data.is_discarded())
66 {
67 log<level::ERR>("Parsing channel cipher suites JSON failed");
68 elog<InternalFailure>();
69 }
70
71 // Byte 1 is reserved
72 cipherList.push_back(0x00);
73
74 for (const auto& record : data)
75 {
76 cipherList.push_back(record.value(cipher, 0));
77 }
78
79 return cipherList;
80}
81} // namespace cipher
82
83namespace ipmi
84{
85namespace transport
86{
87
William A. Kennington IIIc514d872019-04-06 18:19:38 -070088// D-Bus Network Daemon definitions
89constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
90constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
91
92constexpr auto INTF_SYSTEMCONFIG =
93 "xyz.openbmc_project.Network.SystemConfiguration";
94constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
95constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
96constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
97constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070098constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
99constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
100 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700101constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
102constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
103
104/** @brief Generic paramters for different address families */
105template <int family>
106struct AddrFamily
107{
108};
109
110/** @brief Parameter specialization for IPv4 */
111template <>
112struct AddrFamily<AF_INET>
113{
114 using addr = in_addr;
115 static constexpr auto protocol = IP::Protocol::IPv4;
116 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
117 static constexpr uint8_t defaultPrefix = 32;
118 static constexpr char propertyGateway[] = "DefaultGateway";
119};
120
William A. Kennington III16064aa2019-04-13 17:44:53 -0700121/** @brief Parameter specialization for IPv6 */
122template <>
123struct AddrFamily<AF_INET6>
124{
125 using addr = in6_addr;
126 static constexpr auto protocol = IP::Protocol::IPv6;
127 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
128 static constexpr uint8_t defaultPrefix = 128;
129 static constexpr char propertyGateway[] = "DefaultGateway6";
130};
131
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700132/** @brief Valid address origins for IPv4 */
133const std::unordered_set<IP::AddressOrigin> originsV4 = {
134 IP::AddressOrigin::Static,
135 IP::AddressOrigin::DHCP,
136};
137
William A. Kennington III16064aa2019-04-13 17:44:53 -0700138/** @brief Valid address origins for IPv6 */
139const std::unordered_set<IP::AddressOrigin> originsV6Static = {
140 IP::AddressOrigin::Static};
141const std::unordered_set<IP::AddressOrigin> originsV6Dynamic = {
142 IP::AddressOrigin::DHCP,
143 IP::AddressOrigin::SLAAC,
144};
145
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700146/** @brief Interface IP Address configuration parameters */
147template <int family>
148struct IfAddr
149{
150 std::string path;
151 typename AddrFamily<family>::addr address;
152 IP::AddressOrigin origin;
153 uint8_t prefix;
154};
155
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700156/** @brief Interface Neighbor configuration parameters */
157template <int family>
158struct IfNeigh
159{
160 std::string path;
161 typename AddrFamily<family>::addr ip;
162 ether_addr mac;
163};
164
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700165static constexpr uint8_t oemCmdStart = 192;
166static constexpr uint8_t oemCmdEnd = 255;
167
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700168/** @brief A trivial helper used to determine if two PODs are equal
169 *
170 * @params[in] a - The first object to compare
171 * @params[in] b - The second object to compare
172 * @return True if the objects are the same bytewise
173 */
174template <typename T>
175bool equal(const T& a, const T& b)
176{
177 static_assert(std::is_trivially_copyable_v<T>);
178 return std::memcmp(&a, &b, sizeof(T)) == 0;
179}
180
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700181/** @brief Copies bytes from an array into a trivially copyable container
182 *
183 * @params[out] t - The container receiving the data
184 * @params[in] bytes - The data to copy
185 */
186template <size_t N, typename T>
187void copyInto(T& t, const std::array<uint8_t, N>& bytes)
188{
189 static_assert(std::is_trivially_copyable_v<T>);
190 static_assert(N == sizeof(T));
191 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800192}
193
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700194/** @brief Gets a generic view of the bytes in the input container
195 *
196 * @params[in] t - The data to reference
197 * @return A string_view referencing the bytes in the container
198 */
199template <typename T>
200std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600201{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700202 static_assert(std::is_trivially_copyable_v<T>);
203 return {reinterpret_cast<const char*>(&t), sizeof(T)};
204}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530205
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700206/** @brief The dbus parameters for the interface corresponding to a channel
207 * This helps reduce the number of mapper lookups we need for each
208 * query and simplifies finding the VLAN interface if needed.
209 */
210struct ChannelParams
211{
212 /** @brief The channel ID */
213 int id;
214 /** @brief channel name for the interface */
215 std::string ifname;
216 /** @brief Name of the service on the bus */
217 std::string service;
218 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
219 std::string ifPath;
220 /** @brief Logical adapter path used for address assignment */
221 std::string logicalPath;
222};
223
224/** @brief Determines the ethernet interface name corresponding to a channel
225 * Tries to map a VLAN object first so that the address information
226 * is accurate. Otherwise it gets the standard ethernet interface.
227 *
228 * @param[in] bus - The bus object used for lookups
229 * @param[in] channel - The channel id corresponding to an ethernet interface
230 * @return Ethernet interface service and object path if it exists
231 */
232std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
233 uint8_t channel)
234{
235 auto ifname = getChannelName(channel);
236 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800237 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700238 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800239 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800240
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700241 // Enumerate all VLAN + ETHERNET interfaces
242 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
243 "GetSubTree");
244 req.append(PATH_ROOT, 0,
245 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
246 auto reply = bus.call(req);
247 ObjectTree objs;
248 reply.read(objs);
249
250 ChannelParams params;
251 for (const auto& [path, impls] : objs)
252 {
253 if (path.find(ifname) == path.npos)
254 {
255 continue;
256 }
257 for (const auto& [service, intfs] : impls)
258 {
259 bool vlan = false;
260 bool ethernet = false;
261 for (const auto& intf : intfs)
262 {
263 if (intf == INTF_VLAN)
264 {
265 vlan = true;
266 }
267 else if (intf == INTF_ETHERNET)
268 {
269 ethernet = true;
270 }
271 }
272 if (params.service.empty() && (vlan || ethernet))
273 {
274 params.service = service;
275 }
276 if (params.ifPath.empty() && !vlan && ethernet)
277 {
278 params.ifPath = path;
279 }
280 if (params.logicalPath.empty() && vlan)
281 {
282 params.logicalPath = path;
283 }
284 }
285 }
286
287 // We must have a path for the underlying interface
288 if (params.ifPath.empty())
289 {
290 return std::nullopt;
291 }
292 // We don't have a VLAN so the logical path is the same
293 if (params.logicalPath.empty())
294 {
295 params.logicalPath = params.ifPath;
296 }
297
298 params.id = channel;
299 params.ifname = std::move(ifname);
300 return std::move(params);
301}
302
303/** @brief A trivial helper around maybeGetChannelParams() that throws an
304 * exception when it is unable to acquire parameters for the channel.
305 *
306 * @param[in] bus - The bus object used for lookups
307 * @param[in] channel - The channel id corresponding to an ethernet interface
308 * @return Ethernet interface service and object path
309 */
310ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
311{
312 auto params = maybeGetChannelParams(bus, channel);
313 if (!params)
314 {
315 log<level::ERR>("Failed to get channel params",
316 entry("CHANNEL=%" PRIu8, channel));
317 elog<InternalFailure>();
318 }
319 return std::move(*params);
320}
321
322/** @brief Wraps the phosphor logging method to insert some additional metadata
323 *
324 * @param[in] params - The parameters for the channel
325 * ...
326 */
327template <auto level, typename... Args>
328auto logWithChannel(const ChannelParams& params, Args&&... args)
329{
330 return log<level>(std::forward<Args>(args)...,
331 entry("CHANNEL=%d", params.id),
332 entry("IFNAME=%s", params.ifname.c_str()));
333}
334template <auto level, typename... Args>
335auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
336{
337 if (params)
338 {
339 return logWithChannel<level>(*params, std::forward<Args>(args)...);
340 }
341 return log<level>(std::forward<Args>(args)...);
342}
343
344/** @brief Trivializes using parameter getter functions by providing a bus
345 * and channel parameters automatically.
346 *
347 * @param[in] channel - The channel id corresponding to an ethernet interface
348 * ...
349 */
350template <auto func, typename... Args>
351auto channelCall(uint8_t channel, Args&&... args)
352{
353 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
354 auto params = getChannelParams(bus, channel);
355 return std::invoke(func, bus, params, std::forward<Args>(args)...);
356}
357
358/** @brief Determines if the ethernet interface is using DHCP
359 *
360 * @param[in] bus - The bus object used for lookups
361 * @param[in] params - The parameters for the channel
Johnathan Mantey65265362019-11-14 11:24:19 -0800362 * @return DHCPConf enumeration
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700363 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800364EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus::bus& bus,
365 const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700366{
Johnathan Mantey65265362019-11-14 11:24:19 -0800367 std::string dhcpstr = std::get<std::string>(getDbusProperty(
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700368 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
Johnathan Mantey65265362019-11-14 11:24:19 -0800369 return EthernetInterface::convertDHCPConfFromString(dhcpstr);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700370}
371
Johnathan Mantey65265362019-11-14 11:24:19 -0800372/** @brief Sets the DHCP v4 state on the given interface
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700373 *
Johnathan Mantey65265362019-11-14 11:24:19 -0800374 * @param[in] bus - The bus object used for lookups
375 * @param[in] params - The parameters for the channel
376 * @param[in] requestedDhcp - DHCP state to assign
377 * (EthernetInterface::DHCPConf::none,
378 * EthernetInterface::DHCPConf::v4,
379 * EthernetInterface::DHCPConf::v6,
380 * EthernetInterface::DHCPConf::both)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700381 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800382void setDHCPv4Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
383 const EthernetInterface::DHCPConf requestedDhcp)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700384{
Johnathan Mantey65265362019-11-14 11:24:19 -0800385 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
386 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
387
388 if ((currentDhcp == EthernetInterface::DHCPConf::v6) &&
389 (requestedDhcp == EthernetInterface::DHCPConf::v4))
390 {
391 nextDhcp = EthernetInterface::DHCPConf::both;
392 }
393 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
394 (requestedDhcp == EthernetInterface::DHCPConf::v4))
395
396 {
397 nextDhcp = requestedDhcp;
398 }
399 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
400 {
401 if (currentDhcp == EthernetInterface::DHCPConf::both)
402 {
403 nextDhcp = EthernetInterface::DHCPConf::v6;
404 }
405 else if (currentDhcp == EthernetInterface::DHCPConf::v4)
406 {
407 nextDhcp = EthernetInterface::DHCPConf::none;
408 }
409 }
410 else
411 {
412 nextDhcp = currentDhcp;
413 }
414 std::string newDhcp =
415 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
416 nextDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700417 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800418 "DHCPEnabled", newDhcp);
419}
420
421/** @brief Sets the DHCP v6 state on the given interface
422 *
423 * @param[in] bus - The bus object used for lookups
424 * @param[in] params - The parameters for the channel
425 * @param[in] requestedDhcp - DHCP state to assign (none, v6, both)
426 * @param[in] defaultMode - True: Use algorithmic assignment
427 * False: requestedDhcp assigned unconditionally
428 */
429void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
430 const EthernetInterface::DHCPConf requestedDhcp,
431 const bool defaultMode = true)
432{
433 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
434 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
435
436 if (defaultMode)
437 {
438 if ((currentDhcp == EthernetInterface::DHCPConf::v4) &&
439 (requestedDhcp == EthernetInterface::DHCPConf::v6))
440 {
441 nextDhcp = EthernetInterface::DHCPConf::both;
442 }
443 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
444 (requestedDhcp == EthernetInterface::DHCPConf::v6))
445
446 {
447 nextDhcp = requestedDhcp;
448 }
449 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
450 {
451 if (currentDhcp == EthernetInterface::DHCPConf::both)
452 {
453 nextDhcp = EthernetInterface::DHCPConf::v4;
454 }
455 else if (currentDhcp == EthernetInterface::DHCPConf::v6)
456 {
457 nextDhcp = EthernetInterface::DHCPConf::none;
458 }
459 }
460 else
461 {
462 nextDhcp = currentDhcp;
463 }
464 }
465 else
466 {
467 // allow the v6 call to set any value
468 nextDhcp = requestedDhcp;
469 }
470
471 std::string newDhcp =
472 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
473 nextDhcp);
474 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
475 "DHCPEnabled", newDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700476}
477
478/** @brief Converts a human readable MAC string into MAC bytes
479 *
480 * @param[in] mac - The MAC string
481 * @return MAC in bytes
482 */
483ether_addr stringToMAC(const char* mac)
484{
485 const ether_addr* ret = ether_aton(mac);
486 if (ret == nullptr)
487 {
488 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
489 elog<InternalFailure>();
490 }
491 return *ret;
492}
493
494/** @brief Determines the MAC of the ethernet interface
495 *
496 * @param[in] bus - The bus object used for lookups
497 * @param[in] params - The parameters for the channel
498 * @return The configured mac address
499 */
500ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
501{
502 auto macStr = std::get<std::string>(getDbusProperty(
503 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
504 return stringToMAC(macStr.c_str());
505}
506
507/** @brief Sets the system value for MAC address on the given interface
508 *
509 * @param[in] bus - The bus object used for lookups
510 * @param[in] params - The parameters for the channel
511 * @param[in] mac - MAC address to apply
512 */
513void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
514 const ether_addr& mac)
515{
516 std::string macStr = ether_ntoa(&mac);
517 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
518 macStr);
519}
520
521/** @brief Turns an IP address string into the network byte order form
522 * NOTE: This version strictly validates family matches
523 *
524 * @param[in] address - The string form of the address
525 * @return A network byte order address or none if conversion failed
526 */
527template <int family>
528std::optional<typename AddrFamily<family>::addr>
529 maybeStringToAddr(const char* address)
530{
531 typename AddrFamily<family>::addr ret;
532 if (inet_pton(family, address, &ret) == 1)
533 {
534 return ret;
535 }
536 return std::nullopt;
537}
538
539/** @brief Turns an IP address string into the network byte order form
540 * NOTE: This version strictly validates family matches
541 *
542 * @param[in] address - The string form of the address
543 * @return A network byte order address
544 */
545template <int family>
546typename AddrFamily<family>::addr stringToAddr(const char* address)
547{
548 auto ret = maybeStringToAddr<family>(address);
549 if (!ret)
550 {
551 log<level::ERR>("Failed to convert IP Address",
552 entry("FAMILY=%d", family),
553 entry("ADDRESS=%s", address));
554 elog<InternalFailure>();
555 }
556 return *ret;
557}
558
559/** @brief Turns an IP address in network byte order into a string
560 *
561 * @param[in] address - The string form of the address
562 * @return A network byte order address
563 */
564template <int family>
565std::string addrToString(const typename AddrFamily<family>::addr& address)
566{
567 std::string ret(AddrFamily<family>::maxStrLen, '\0');
568 inet_ntop(family, &address, ret.data(), ret.size());
569 ret.resize(strlen(ret.c_str()));
570 return ret;
571}
572
573/** @brief Retrieves the current gateway for the address family on the system
574 * NOTE: The gateway is currently system wide and not per channel
575 *
576 * @param[in] bus - The bus object used for lookups
577 * @param[in] params - The parameters for the channel
578 * @return An address representing the gateway address if it exists
579 */
580template <int family>
581std::optional<typename AddrFamily<family>::addr>
582 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
583{
584 auto gatewayStr = std::get<std::string>(getDbusProperty(
585 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
586 AddrFamily<family>::propertyGateway));
587 if (gatewayStr.empty())
588 {
589 return std::nullopt;
590 }
591 return stringToAddr<family>(gatewayStr.c_str());
592}
593
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700594/** @brief A lazy lookup mechanism for iterating over object properties stored
595 * in DBus. This will only perform the object lookup when needed, and
596 * retains a cache of previous lookups to speed up future iterations.
597 */
598class ObjectLookupCache
599{
600 public:
601 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
602
603 /** @brief Creates a new ObjectLookupCache for the interface on the bus
604 * NOTE: The inputs to this object must outlive the object since
605 * they are only referenced by it.
606 *
607 * @param[in] bus - The bus object used for lookups
608 * @param[in] params - The parameters for the channel
609 * @param[in] intf - The interface we are looking up
610 */
611 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
612 const char* intf) :
613 bus(bus),
614 params(params), intf(intf),
615 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
616 {
617 }
618
619 class iterator : public ObjectTree::const_iterator
620 {
621 public:
622 using value_type = PropertiesCache::value_type;
623
624 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
625 ObjectTree::const_iterator(it), container(container),
626 ret(container.cache.end())
627 {
628 }
629 value_type& operator*()
630 {
631 ret = container.get(ObjectTree::const_iterator::operator*().first);
632 return *ret;
633 }
634 value_type* operator->()
635 {
636 return &operator*();
637 }
638
639 private:
640 ObjectLookupCache& container;
641 PropertiesCache::iterator ret;
642 };
643
644 iterator begin() noexcept
645 {
646 return iterator(objs.begin(), *this);
647 }
648
649 iterator end() noexcept
650 {
651 return iterator(objs.end(), *this);
652 }
653
654 private:
655 sdbusplus::bus::bus& bus;
656 const ChannelParams& params;
657 const char* const intf;
658 const ObjectTree objs;
659 PropertiesCache cache;
660
661 /** @brief Gets a cached copy of the object properties if possible
662 * Otherwise performs a query on DBus to look them up
663 *
664 * @param[in] path - The object path to lookup
665 * @return An iterator for the specified object path + properties
666 */
667 PropertiesCache::iterator get(const std::string& path)
668 {
669 auto it = cache.find(path);
670 if (it != cache.end())
671 {
672 return it;
673 }
674 auto properties = getAllDbusProperties(bus, params.service, path, intf);
675 return cache.insert({path, std::move(properties)}).first;
676 }
677};
678
679/** @brief Searches the ip object lookup cache for an address matching
680 * the input parameters. NOTE: The index lacks stability across address
681 * changes since the network daemon has no notion of stable indicies.
682 *
683 * @param[in] bus - The bus object used for lookups
684 * @param[in] params - The parameters for the channel
685 * @param[in] idx - The index of the desired address on the interface
686 * @param[in] origins - The allowed origins for the address objects
687 * @param[in] ips - The object lookup cache holding all of the address info
688 * @return The address and prefix if it was found
689 */
690template <int family>
691std::optional<IfAddr<family>>
692 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
693 uint8_t idx,
694 const std::unordered_set<IP::AddressOrigin>& origins,
695 ObjectLookupCache& ips)
696{
697 for (const auto& [path, properties] : ips)
698 {
699 const auto& addrStr = std::get<std::string>(properties.at("Address"));
700 auto addr = maybeStringToAddr<family>(addrStr.c_str());
701 if (!addr)
702 {
703 continue;
704 }
705
706 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
707 std::get<std::string>(properties.at("Origin")));
708 if (origins.find(origin) == origins.end())
709 {
710 continue;
711 }
712
713 if (idx > 0)
714 {
715 idx--;
716 continue;
717 }
718
719 IfAddr<family> ifaddr;
720 ifaddr.path = path;
721 ifaddr.address = *addr;
722 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
723 ifaddr.origin = origin;
724 return std::move(ifaddr);
725 }
726
727 return std::nullopt;
728}
729
730/** @brief Trivial helper around findIfAddr that simplifies calls
731 * for one off lookups. Don't use this if you intend to do multiple
732 * lookups at a time.
733 *
734 * @param[in] bus - The bus object used for lookups
735 * @param[in] params - The parameters for the channel
736 * @param[in] idx - The index of the desired address on the interface
737 * @param[in] origins - The allowed origins for the address objects
738 * @return The address and prefix if it was found
739 */
740template <int family>
741auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
742 uint8_t idx,
743 const std::unordered_set<IP::AddressOrigin>& origins)
744{
745 ObjectLookupCache ips(bus, params, INTF_IP);
746 return findIfAddr<family>(bus, params, idx, origins, ips);
747}
748
749/** @brief Deletes the dbus object. Ignores empty objects or objects that are
750 * missing from the bus.
751 *
752 * @param[in] bus - The bus object used for lookups
753 * @param[in] service - The name of the service
754 * @param[in] path - The path of the object to delete
755 */
756void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
757 const std::string& path)
758{
759 if (path.empty())
760 {
761 return;
762 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530763 try
tomjose26e17732016-03-03 08:52:51 -0600764 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700765 auto req = bus.new_method_call(service.c_str(), path.c_str(),
766 ipmi::DELETE_INTERFACE, "Delete");
767 bus.call_noreply(req);
768 }
769 catch (const sdbusplus::exception::SdBusError& e)
770 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000771 if (strcmp(e.name(),
772 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
773 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600774 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700775 // We want to rethrow real errors
776 throw;
tomjose26e17732016-03-03 08:52:51 -0600777 }
778 }
tomjose26e17732016-03-03 08:52:51 -0600779}
780
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700781/** @brief Sets the address info configured for the interface
782 * If a previous address path exists then it will be removed
783 * before the new address is added.
784 *
785 * @param[in] bus - The bus object used for lookups
786 * @param[in] params - The parameters for the channel
787 * @param[in] address - The address of the new IP
788 * @param[in] prefix - The prefix of the new IP
789 */
790template <int family>
791void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
792 const typename AddrFamily<family>::addr& address,
793 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530794{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700795 auto newreq =
796 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
797 INTF_IP_CREATE, "IP");
798 std::string protocol =
799 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
800 AddrFamily<family>::protocol);
801 newreq.append(protocol, addrToString<family>(address), prefix, "");
802 bus.call_noreply(newreq);
803}
Tom Josepha30c8d32018-03-22 02:15:03 +0530804
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700805/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
806 *
807 * @param[in] bus - The bus object used for lookups
808 * @param[in] params - The parameters for the channel
809 * @return The address and prefix if found
810 */
811auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530812{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700813 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
814}
Tom Josepha30c8d32018-03-22 02:15:03 +0530815
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700816/** @brief Reconfigures the IPv4 address info configured for the interface
817 *
818 * @param[in] bus - The bus object used for lookups
819 * @param[in] params - The parameters for the channel
820 * @param[in] address - The new address if specified
821 * @param[in] prefix - The new address prefix if specified
822 */
823void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
824 const std::optional<in_addr>& address,
825 std::optional<uint8_t> prefix)
826{
827 auto ifaddr = getIfAddr4(bus, params);
828 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530829 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700830 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530831 elog<InternalFailure>();
832 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700833 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
834 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530835 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700836 fallbackPrefix = ifaddr->prefix;
837 deleteObjectIfExists(bus, params.service, ifaddr->path);
838 }
839 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
840 prefix.value_or(fallbackPrefix));
841}
842
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700843template <int family>
844std::optional<IfNeigh<family>>
845 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
846 const typename AddrFamily<family>::addr& ip,
847 ObjectLookupCache& neighbors)
848{
849 const auto state =
850 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
851 Neighbor::State::Permanent);
852 for (const auto& [path, neighbor] : neighbors)
853 {
854 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
855 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
856 if (!neighIP)
857 {
858 continue;
859 }
860 if (!equal(*neighIP, ip))
861 {
862 continue;
863 }
864 if (state != std::get<std::string>(neighbor.at("State")))
865 {
866 continue;
867 }
868
869 IfNeigh<family> ret;
870 ret.path = path;
871 ret.ip = ip;
872 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
873 ret.mac = stringToMAC(macStr.c_str());
874 return std::move(ret);
875 }
876
877 return std::nullopt;
878}
879
880template <int family>
881void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
882 const typename AddrFamily<family>::addr& address,
883 const ether_addr& mac)
884{
885 auto newreq =
886 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
887 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
888 std::string macStr = ether_ntoa(&mac);
889 newreq.append(addrToString<family>(address), macStr);
890 bus.call_noreply(newreq);
891}
892
893/** @brief Sets the system wide value for the default gateway
894 *
895 * @param[in] bus - The bus object used for lookups
896 * @param[in] params - The parameters for the channel
897 * @param[in] gateway - Gateway address to apply
898 */
899template <int family>
900void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
901 const typename AddrFamily<family>::addr& address)
902{
903 // Save the old gateway MAC address if it exists so we can recreate it
904 auto gateway = getGatewayProperty<family>(bus, params);
905 std::optional<IfNeigh<family>> neighbor;
906 if (gateway)
907 {
908 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
909 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
910 }
911
912 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
913 AddrFamily<family>::propertyGateway,
914 addrToString<family>(address));
915
916 // Restore the gateway MAC if we had one
917 if (neighbor)
918 {
919 deleteObjectIfExists(bus, params.service, neighbor->path);
920 createNeighbor<family>(bus, params, address, neighbor->mac);
921 }
922}
923
924template <int family>
925std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
926 const ChannelParams& params,
927 ObjectLookupCache& neighbors)
928{
929 auto gateway = getGatewayProperty<family>(bus, params);
930 if (!gateway)
931 {
932 return std::nullopt;
933 }
934
935 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
936}
937
938template <int family>
939std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
940 const ChannelParams& params)
941{
942 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
943 return findGatewayNeighbor<family>(bus, params, neighbors);
944}
945
946template <int family>
947void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
948 const ChannelParams& params, const ether_addr& mac)
949{
950 auto gateway = getGatewayProperty<family>(bus, params);
951 if (!gateway)
952 {
953 log<level::ERR>("Tried to set Gateway MAC without Gateway");
954 elog<InternalFailure>();
955 }
956
957 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
958 auto neighbor =
959 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
960 if (neighbor)
961 {
962 deleteObjectIfExists(bus, params.service, neighbor->path);
963 }
964
965 createNeighbor<family>(bus, params, *gateway, mac);
966}
967
William A. Kennington III16064aa2019-04-13 17:44:53 -0700968/** @brief Deconfigures the IPv6 address info configured for the interface
969 *
970 * @param[in] bus - The bus object used for lookups
971 * @param[in] params - The parameters for the channel
972 * @param[in] idx - The address index to operate on
973 */
974void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
975 uint8_t idx)
976{
977 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
978 if (ifaddr)
979 {
980 deleteObjectIfExists(bus, params.service, ifaddr->path);
981 }
982}
983
984/** @brief Reconfigures the IPv6 address info configured for the interface
985 *
986 * @param[in] bus - The bus object used for lookups
987 * @param[in] params - The parameters for the channel
988 * @param[in] idx - The address index to operate on
989 * @param[in] address - The new address
990 * @param[in] prefix - The new address prefix
991 */
992void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
993 uint8_t idx, const in6_addr& address, uint8_t prefix)
994{
995 deconfigureIfAddr6(bus, params, idx);
996 createIfAddr<AF_INET6>(bus, params, address, prefix);
997}
998
999/** @brief Converts the AddressOrigin into an IPv6Source
1000 *
1001 * @param[in] origin - The DBus Address Origin to convert
1002 * @return The IPv6Source version of the origin
1003 */
1004IPv6Source originToSourceType(IP::AddressOrigin origin)
1005{
1006 switch (origin)
1007 {
1008 case IP::AddressOrigin::Static:
1009 return IPv6Source::Static;
1010 case IP::AddressOrigin::DHCP:
1011 return IPv6Source::DHCP;
1012 case IP::AddressOrigin::SLAAC:
1013 return IPv6Source::SLAAC;
1014 default:
1015 {
1016 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
1017 convertForMessage(origin);
1018 log<level::ERR>(
1019 "Invalid IP::AddressOrigin conversion to IPv6Source",
1020 entry("ORIGIN=%s", originStr.c_str()));
1021 elog<InternalFailure>();
1022 }
1023 }
1024}
1025
1026/** @brief Packs the IPMI message response with IPv6 address data
1027 *
1028 * @param[out] ret - The IPMI response payload to be packed
1029 * @param[in] channel - The channel id corresponding to an ethernet interface
1030 * @param[in] set - The set selector for determining address index
1031 * @param[in] origins - Set of valid origins for address filtering
1032 */
1033void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
1034 const std::unordered_set<IP::AddressOrigin>& origins)
1035{
1036 auto source = IPv6Source::Static;
1037 bool enabled = false;
1038 in6_addr addr{};
1039 uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
1040 auto status = IPv6AddressStatus::Disabled;
1041
1042 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
1043 if (ifaddr)
1044 {
1045 source = originToSourceType(ifaddr->origin);
1046 enabled = true;
1047 addr = ifaddr->address;
1048 prefix = ifaddr->prefix;
1049 status = IPv6AddressStatus::Active;
1050 }
1051
1052 ret.pack(set);
1053 ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled);
1054 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
1055 ret.pack(prefix);
1056 ret.pack(static_cast<uint8_t>(status));
1057}
1058
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001059/** @brief Gets the vlan ID configured on the interface
1060 *
1061 * @param[in] bus - The bus object used for lookups
1062 * @param[in] params - The parameters for the channel
1063 * @return VLAN id or the standard 0 for no VLAN
1064 */
1065uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
1066{
1067 // VLAN devices will always have a separate logical object
1068 if (params.ifPath == params.logicalPath)
1069 {
1070 return 0;
1071 }
1072
1073 auto vlan = std::get<uint32_t>(getDbusProperty(
1074 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
1075 if ((vlan & VLAN_VALUE_MASK) != vlan)
1076 {
1077 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
1078 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +05301079 elog<InternalFailure>();
1080 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001081 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +05301082}
1083
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001084/** @brief Deletes all of the possible configuration parameters for a channel
1085 *
1086 * @param[in] bus - The bus object used for lookups
1087 * @param[in] params - The parameters for the channel
1088 */
1089void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001090{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001091 // Delete all objects associated with the interface
1092 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
1093 "GetSubTree");
1094 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
1095 auto objreply = bus.call(objreq);
1096 ObjectTree objs;
1097 objreply.read(objs);
1098 for (const auto& [path, impls] : objs)
1099 {
1100 if (path.find(params.ifname) == path.npos)
1101 {
1102 continue;
1103 }
1104 for (const auto& [service, intfs] : impls)
1105 {
1106 deleteObjectIfExists(bus, service, path);
1107 }
1108 // Update params to reflect the deletion of vlan
1109 if (path == params.logicalPath)
1110 {
1111 params.logicalPath = params.ifPath;
1112 }
1113 }
1114
1115 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -08001116 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001117}
1118
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001119/** @brief Creates a new VLAN on the specified interface
1120 *
1121 * @param[in] bus - The bus object used for lookups
1122 * @param[in] params - The parameters for the channel
1123 * @param[in] vlan - The id of the new vlan
1124 */
1125void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +05301126{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001127 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301128 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001129 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301130 }
1131
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001132 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
1133 INTF_VLAN_CREATE, "VLAN");
1134 req.append(params.ifname, static_cast<uint32_t>(vlan));
1135 auto reply = bus.call(req);
1136 sdbusplus::message::object_path newPath;
1137 reply.read(newPath);
1138 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301139}
1140
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001141/** @brief Performs the necessary reconfiguration to change the VLAN
1142 *
1143 * @param[in] bus - The bus object used for lookups
1144 * @param[in] params - The parameters for the channel
1145 * @param[in] vlan - The new vlan id to use
1146 */
1147void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
1148 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001149{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001150 // Unfortunatetly we don't have built-in functions to migrate our interface
1151 // customizations to new VLAN interfaces, or have some kind of decoupling.
1152 // We therefore must retain all of our old information, setup the new VLAN
1153 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +08001154
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001155 // Save info from the old logical interface
1156 ObjectLookupCache ips(bus, params, INTF_IP);
1157 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001158 std::vector<IfAddr<AF_INET6>> ifaddrs6;
1159 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
1160 {
1161 auto ifaddr6 =
1162 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
1163 if (!ifaddr6)
1164 {
1165 break;
1166 }
1167 ifaddrs6.push_back(std::move(*ifaddr6));
1168 }
Johnathan Mantey65265362019-11-14 11:24:19 -08001169 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001170 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1171 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001172 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001173
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001174 deconfigureChannel(bus, params);
1175 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001176
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001177 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -08001178 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001179 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001180 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001181 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001182 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001183 for (const auto& ifaddr6 : ifaddrs6)
1184 {
1185 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
1186 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001187 if (neighbor4)
1188 {
1189 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
1190 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001191 if (neighbor6)
1192 {
1193 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
1194 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001195}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001196
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001197/** @brief Turns a prefix into a netmask
1198 *
1199 * @param[in] prefix - The prefix length
1200 * @return The netmask
1201 */
1202in_addr prefixToNetmask(uint8_t prefix)
1203{
1204 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001205 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001206 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
1207 elog<InternalFailure>();
1208 }
1209 if (prefix == 0)
1210 {
1211 // Avoids 32-bit lshift by 32 UB
1212 return {};
1213 }
1214 return {htobe32(~UINT32_C(0) << (32 - prefix))};
1215}
1216
1217/** @brief Turns a a netmask into a prefix length
1218 *
1219 * @param[in] netmask - The netmask in byte form
1220 * @return The prefix length
1221 */
1222uint8_t netmaskToPrefix(in_addr netmask)
1223{
1224 uint32_t x = be32toh(netmask.s_addr);
1225 if ((~x & (~x + 1)) != 0)
1226 {
1227 char maskStr[INET_ADDRSTRLEN];
1228 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
1229 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
1230 elog<InternalFailure>();
1231 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -08001232 return static_cast<bool>(x)
1233 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
1234 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001235}
1236
1237// We need to store this value so it can be returned to the client
1238// It is volatile so safe to store in daemon memory.
1239static std::unordered_map<uint8_t, SetStatus> setStatus;
1240
1241// Until we have good support for fixed versions of IPMI tool
1242// we need to return the VLAN id for disabled VLANs. The value is only
1243// used for verification that a disable operation succeeded and will only
1244// be sent if our system indicates that vlans are disabled.
1245static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
1246
1247/** @brief Gets the set status for the channel if it exists
1248 * Otherise populates and returns the default value.
1249 *
1250 * @param[in] channel - The channel id corresponding to an ethernet interface
1251 * @return A reference to the SetStatus for the channel
1252 */
1253SetStatus& getSetStatus(uint8_t channel)
1254{
1255 auto it = setStatus.find(channel);
1256 if (it != setStatus.end())
1257 {
1258 return it->second;
1259 }
1260 return setStatus[channel] = SetStatus::Complete;
1261}
1262
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001263/**
1264 * Define placeholder command handlers for the OEM Extension bytes for the Set
1265 * LAN Configuration Parameters and Get LAN Configuration Parameters
1266 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
1267 * functions below to be overridden.
1268 * To create handlers for your own proprietary command set:
1269 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
1270 * recipe
1271 * Create C++ file(s) that define IPMI handler functions matching the
1272 * function names below (i.e. setLanOem). The default name for the
1273 * transport IPMI commands is transporthandler_oem.cpp.
1274 * Add:
1275 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
1276 * Create a do_compile_prepend()/do_install_append method in your
1277 * bbappend file to copy the file to the build directory.
1278 * Add:
1279 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
1280 * # Copy the "strong" functions into the working directory, overriding the
1281 * # placeholder functions.
1282 * do_compile_prepend(){
1283 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
1284 * }
1285 *
1286 * # Clean up after complilation has completed
1287 * do_install_append(){
1288 * rm -f ${S}/transporthandler_oem.cpp
1289 * }
1290 *
1291 */
1292
1293/**
1294 * Define the placeholder OEM commands as having weak linkage. Create
1295 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
1296 * file. The functions defined there must not have the "weak" attribute
1297 * applied to them.
1298 */
1299RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1300 __attribute__((weak));
1301RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1302 uint8_t set, uint8_t block)
1303 __attribute__((weak));
1304
1305RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1306{
1307 req.trailingOk = true;
1308 return response(ccParamNotSupported);
1309}
1310
1311RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1312 uint8_t set, uint8_t block)
1313{
1314 return response(ccParamNotSupported);
1315}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301316/**
1317 * @brief is MAC address valid.
1318 *
1319 * This function checks whether the MAC address is valid or not.
1320 *
1321 * @param[in] mac - MAC address.
1322 * @return true if MAC address is valid else retun false.
1323 **/
1324bool isValidMACAddress(const ether_addr& mac)
1325{
1326 // check if mac address is empty
1327 if (equal(mac, ether_addr{}))
1328 {
1329 return false;
1330 }
1331 // we accept only unicast MAC addresses and same thing has been checked in
1332 // phosphor-network layer. If the least significant bit of the first octet
1333 // is set to 1, it is multicast MAC else it is unicast MAC address.
1334 if (mac.ether_addr_octet[0] & 1)
1335 {
1336 return false;
1337 }
1338 return true;
1339}
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001340
vijayabharathix shettycc769252020-02-27 17:52:20 +00001341RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1342 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001343{
vijayabharathix shettycc769252020-02-27 17:52:20 +00001344 const uint8_t channel = convertCurrentChannelNum(
1345 static_cast<uint8_t>(channelBits), ctx->channel);
1346 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001347 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001348 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001349 req.trailingOk = true;
1350 return responseInvalidFieldRequest();
1351 }
1352
1353 switch (static_cast<LanParam>(parameter))
1354 {
1355 case LanParam::SetStatus:
1356 {
1357 uint2_t flag;
1358 uint6_t rsvd;
1359 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1360 {
1361 return responseReqDataLenInvalid();
1362 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001363 if (rsvd)
1364 {
1365 return responseInvalidFieldRequest();
1366 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001367 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1368 switch (status)
1369 {
1370 case SetStatus::Complete:
1371 {
1372 getSetStatus(channel) = status;
1373 return responseSuccess();
1374 }
1375 case SetStatus::InProgress:
1376 {
1377 auto& storedStatus = getSetStatus(channel);
1378 if (storedStatus == SetStatus::InProgress)
1379 {
1380 return response(ccParamSetLocked);
1381 }
1382 storedStatus = status;
1383 return responseSuccess();
1384 }
1385 case SetStatus::Commit:
1386 if (getSetStatus(channel) != SetStatus::InProgress)
1387 {
1388 return responseInvalidFieldRequest();
1389 }
1390 return responseSuccess();
1391 }
1392 return response(ccParamNotSupported);
1393 }
1394 case LanParam::AuthSupport:
1395 {
1396 req.trailingOk = true;
1397 return response(ccParamReadOnly);
1398 }
1399 case LanParam::AuthEnables:
1400 {
1401 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001402 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001403 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001404 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001405 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001406 EthernetInterface::DHCPConf dhcp =
1407 channelCall<getDHCPProperty>(channel);
1408 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1409 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001410 {
1411 return responseCommandNotAvailable();
1412 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001413 in_addr ip;
1414 std::array<uint8_t, sizeof(ip)> bytes;
1415 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1416 {
1417 return responseReqDataLenInvalid();
1418 }
1419 copyInto(ip, bytes);
1420 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1421 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301422 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001423 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301424 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001425 uint4_t flag;
1426 uint4_t rsvd;
1427 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1428 {
1429 return responseReqDataLenInvalid();
1430 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001431 if (rsvd)
1432 {
1433 return responseInvalidFieldRequest();
1434 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001435 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1436 {
1437 case IPSrc::DHCP:
1438 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001439 // The IPSrc IPMI command is only for IPv4
1440 // management. Modifying IPv6 state is done using
1441 // a completely different Set LAN Configuration
1442 // subcommand.
1443 channelCall<setDHCPv4Property>(
1444 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001445 return responseSuccess();
1446 }
1447 case IPSrc::Unspecified:
1448 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001449 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001450 channelCall<setDHCPv4Property>(
1451 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001452 return responseSuccess();
1453 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +05301454 case IPSrc::BIOS:
1455 case IPSrc::BMC:
1456 {
1457 return responseInvalidFieldRequest();
1458 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001459 }
1460 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301461 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001462 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301463 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001464 ether_addr mac;
1465 std::array<uint8_t, sizeof(mac)> bytes;
1466 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301467 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001468 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301469 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001470 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301471
1472 if (!isValidMACAddress(mac))
1473 {
1474 return responseInvalidFieldRequest();
1475 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001476 channelCall<setMACProperty>(channel, mac);
1477 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301478 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001479 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301480 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001481 EthernetInterface::DHCPConf dhcp =
1482 channelCall<getDHCPProperty>(channel);
1483 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1484 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001485 {
1486 return responseCommandNotAvailable();
1487 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001488 in_addr netmask;
1489 std::array<uint8_t, sizeof(netmask)> bytes;
1490 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301491 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001492 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301493 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001494 copyInto(netmask, bytes);
1495 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1496 netmaskToPrefix(netmask));
1497 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301498 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001499 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301500 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001501 EthernetInterface::DHCPConf dhcp =
1502 channelCall<getDHCPProperty>(channel);
1503 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1504 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001505 {
1506 return responseCommandNotAvailable();
1507 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001508 in_addr gateway;
1509 std::array<uint8_t, sizeof(gateway)> bytes;
1510 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1511 {
1512 return responseReqDataLenInvalid();
1513 }
1514 copyInto(gateway, bytes);
1515 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1516 return responseSuccess();
1517 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001518 case LanParam::Gateway1MAC:
1519 {
1520 ether_addr gatewayMAC;
1521 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1522 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1523 {
1524 return responseReqDataLenInvalid();
1525 }
1526 copyInto(gatewayMAC, bytes);
1527 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1528 return responseSuccess();
1529 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001530 case LanParam::VLANId:
1531 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301532 uint12_t vlanData = 0;
1533 uint3_t reserved = 0;
1534 bool vlanEnable = 0;
1535
1536 if (req.unpack(vlanData) || req.unpack(reserved) ||
1537 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001538 {
1539 return responseReqDataLenInvalid();
1540 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301541
1542 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001543 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301544 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001545 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301546
1547 uint16_t vlan = static_cast<uint16_t>(vlanData);
1548
1549 if (!vlanEnable)
1550 {
1551 lastDisabledVlan[channel] = vlan;
1552 vlan = 0;
1553 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001554 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1555 {
1556 return responseInvalidFieldRequest();
1557 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301558
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001559 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001560 return responseSuccess();
1561 }
1562 case LanParam::CiphersuiteSupport:
1563 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001564 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001565 {
1566 req.trailingOk = true;
1567 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301568 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001569 case LanParam::IPFamilyEnables:
1570 {
1571 uint8_t enables;
1572 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1573 {
1574 return responseReqDataLenInvalid();
1575 }
1576 switch (static_cast<IPFamilyEnables>(enables))
1577 {
1578 case IPFamilyEnables::DualStack:
1579 return responseSuccess();
1580 case IPFamilyEnables::IPv4Only:
1581 case IPFamilyEnables::IPv6Only:
1582 return response(ccParamNotSupported);
1583 }
1584 return response(ccParamNotSupported);
1585 }
1586 case LanParam::IPv6Status:
1587 {
1588 req.trailingOk = true;
1589 return response(ccParamReadOnly);
1590 }
1591 case LanParam::IPv6StaticAddresses:
1592 {
1593 uint8_t set;
1594 uint7_t rsvd;
1595 bool enabled;
1596 in6_addr ip;
1597 std::array<uint8_t, sizeof(ip)> ipbytes;
1598 uint8_t prefix;
1599 uint8_t status;
1600 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1601 !req.fullyUnpacked())
1602 {
1603 return responseReqDataLenInvalid();
1604 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001605 if (rsvd)
1606 {
1607 return responseInvalidFieldRequest();
1608 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001609 copyInto(ip, ipbytes);
1610 if (enabled)
1611 {
1612 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1613 }
1614 else
1615 {
1616 channelCall<deconfigureIfAddr6>(channel, set);
1617 }
1618 return responseSuccess();
1619 }
1620 case LanParam::IPv6DynamicAddresses:
1621 {
1622 req.trailingOk = true;
1623 return response(ccParamReadOnly);
1624 }
1625 case LanParam::IPv6RouterControl:
1626 {
1627 std::bitset<8> control;
1628 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1629 {
1630 return responseReqDataLenInvalid();
1631 }
1632 std::bitset<8> expected;
Johnathan Mantey65265362019-11-14 11:24:19 -08001633 EthernetInterface::DHCPConf dhcp =
1634 channelCall<getDHCPProperty>(channel);
1635 if ((dhcp == EthernetInterface::DHCPConf::both) |
1636 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001637 {
1638 expected[IPv6RouterControlFlag::Dynamic] = 1;
1639 }
1640 else
1641 {
1642 expected[IPv6RouterControlFlag::Static] = 1;
1643 }
1644 if (expected != control)
1645 {
1646 return responseInvalidFieldRequest();
1647 }
1648 return responseSuccess();
1649 }
1650 case LanParam::IPv6StaticRouter1IP:
1651 {
1652 in6_addr gateway;
1653 std::array<uint8_t, sizeof(gateway)> bytes;
1654 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1655 {
1656 return responseReqDataLenInvalid();
1657 }
1658 copyInto(gateway, bytes);
1659 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1660 return responseSuccess();
1661 }
1662 case LanParam::IPv6StaticRouter1MAC:
1663 {
1664 ether_addr mac;
1665 std::array<uint8_t, sizeof(mac)> bytes;
1666 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1667 {
1668 return responseReqDataLenInvalid();
1669 }
1670 copyInto(mac, bytes);
1671 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1672 return responseSuccess();
1673 }
1674 case LanParam::IPv6StaticRouter1PrefixLength:
1675 {
1676 uint8_t prefix;
1677 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1678 {
1679 return responseReqDataLenInvalid();
1680 }
1681 if (prefix != 0)
1682 {
1683 return responseInvalidFieldRequest();
1684 }
1685 return responseSuccess();
1686 }
1687 case LanParam::IPv6StaticRouter1PrefixValue:
1688 {
1689 std::array<uint8_t, sizeof(in6_addr)> bytes;
1690 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1691 {
1692 return responseReqDataLenInvalid();
1693 }
1694 // Accept any prefix value since our prefix length has to be 0
1695 return responseSuccess();
1696 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001697 case LanParam::cipherSuitePrivilegeLevels:
1698 {
1699 uint8_t reserved;
1700 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1701
1702 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1703 {
1704 return responseReqDataLenInvalid();
1705 }
1706
1707 if (reserved)
1708 {
1709 return responseInvalidFieldRequest();
1710 }
1711
1712 uint8_t resp =
1713 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1714 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1715 if (!resp)
1716 {
1717 return responseSuccess();
1718 }
1719 else
1720 {
1721 req.trailingOk = true;
1722 return response(resp);
1723 }
1724 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301725 }
vishwa1eaea4f2016-02-26 11:57:40 -06001726
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001727 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1728 {
1729 return setLanOem(channel, parameter, req);
1730 }
1731
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001732 req.trailingOk = true;
1733 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001734}
1735
vijayabharathix shettycc769252020-02-27 17:52:20 +00001736RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1737 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001738 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301739{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001740 message::Payload ret;
1741 constexpr uint8_t current_revision = 0x11;
1742 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001743
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001744 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301745 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001746 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301747 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001748
vijayabharathix shettycc769252020-02-27 17:52:20 +00001749 const uint8_t channel = convertCurrentChannelNum(
1750 static_cast<uint8_t>(channelBits), ctx->channel);
1751 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001752 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001753 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001754 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001755 }
1756
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001757 static std::vector<uint8_t> cipherList;
1758 static bool listInit = false;
1759 if (!listInit)
1760 {
1761 try
1762 {
1763 cipherList = cipher::getCipherList();
1764 listInit = true;
1765 }
1766 catch (const std::exception& e)
1767 {
1768 }
1769 }
1770
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001771 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301772 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001773 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301774 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001775 SetStatus status;
1776 try
1777 {
1778 status = setStatus.at(channel);
1779 }
1780 catch (const std::out_of_range&)
1781 {
1782 status = SetStatus::Complete;
1783 }
1784 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1785 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301786 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001787 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301788 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001789 std::bitset<6> support;
1790 ret.pack(support, uint2_t{});
1791 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301792 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001793 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001794 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001795 std::bitset<6> enables;
1796 ret.pack(enables, uint2_t{}); // Callback
1797 ret.pack(enables, uint2_t{}); // User
1798 ret.pack(enables, uint2_t{}); // Operator
1799 ret.pack(enables, uint2_t{}); // Admin
1800 ret.pack(enables, uint2_t{}); // OEM
1801 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001802 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001803 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001804 {
1805 auto ifaddr = channelCall<getIfAddr4>(channel);
1806 in_addr addr{};
1807 if (ifaddr)
1808 {
1809 addr = ifaddr->address;
1810 }
1811 ret.pack(dataRef(addr));
1812 return responseSuccess(std::move(ret));
1813 }
1814 case LanParam::IPSrc:
1815 {
1816 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001817 EthernetInterface::DHCPConf dhcp =
1818 channelCall<getDHCPProperty>(channel);
1819 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1820 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001821 {
1822 src = IPSrc::DHCP;
1823 }
1824 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1825 return responseSuccess(std::move(ret));
1826 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001827 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001828 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001829 ether_addr mac = channelCall<getMACProperty>(channel);
1830 ret.pack(dataRef(mac));
1831 return responseSuccess(std::move(ret));
1832 }
1833 case LanParam::SubnetMask:
1834 {
1835 auto ifaddr = channelCall<getIfAddr4>(channel);
1836 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1837 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301838 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001839 prefix = ifaddr->prefix;
1840 }
1841 in_addr netmask = prefixToNetmask(prefix);
1842 ret.pack(dataRef(netmask));
1843 return responseSuccess(std::move(ret));
1844 }
1845 case LanParam::Gateway1:
1846 {
1847 auto gateway =
1848 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1849 in_addr{});
1850 ret.pack(dataRef(gateway));
1851 return responseSuccess(std::move(ret));
1852 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001853 case LanParam::Gateway1MAC:
1854 {
1855 ether_addr mac{};
1856 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1857 if (neighbor)
1858 {
1859 mac = neighbor->mac;
1860 }
1861 ret.pack(dataRef(mac));
1862 return responseSuccess(std::move(ret));
1863 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001864 case LanParam::VLANId:
1865 {
1866 uint16_t vlan = channelCall<getVLANProperty>(channel);
1867 if (vlan != 0)
1868 {
1869 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301870 }
1871 else
1872 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001873 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301874 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001875 ret.pack(vlan);
1876 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001877 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001878 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001879 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001880 if (getChannelSessionSupport(channel) ==
1881 EChannelSessSupported::none)
1882 {
1883 return responseInvalidFieldRequest();
1884 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001885 if (!listInit)
1886 {
1887 return responseUnspecifiedError();
1888 }
1889 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1890 return responseSuccess(std::move(ret));
1891 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001892 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001893 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001894 if (getChannelSessionSupport(channel) ==
1895 EChannelSessSupported::none)
1896 {
1897 return responseInvalidFieldRequest();
1898 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001899 if (!listInit)
1900 {
1901 return responseUnspecifiedError();
1902 }
1903 ret.pack(cipherList);
1904 return responseSuccess(std::move(ret));
1905 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001906 case LanParam::IPFamilySupport:
1907 {
1908 std::bitset<8> support;
1909 support[IPFamilySupportFlag::IPv6Only] = 0;
1910 support[IPFamilySupportFlag::DualStack] = 1;
1911 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1912 ret.pack(support);
1913 return responseSuccess(std::move(ret));
1914 }
1915 case LanParam::IPFamilyEnables:
1916 {
1917 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1918 return responseSuccess(std::move(ret));
1919 }
1920 case LanParam::IPv6Status:
1921 {
1922 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1923 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1924 std::bitset<8> support;
1925 support[IPv6StatusFlag::DHCP] = 1;
1926 support[IPv6StatusFlag::SLAAC] = 1;
1927 ret.pack(support);
1928 return responseSuccess(std::move(ret));
1929 }
1930 case LanParam::IPv6StaticAddresses:
1931 {
1932 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1933 {
1934 return responseParmOutOfRange();
1935 }
1936 getLanIPv6Address(ret, channel, set, originsV6Static);
1937 return responseSuccess(std::move(ret));
1938 }
1939 case LanParam::IPv6DynamicAddresses:
1940 {
1941 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1942 {
1943 return responseParmOutOfRange();
1944 }
1945 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1946 return responseSuccess(std::move(ret));
1947 }
1948 case LanParam::IPv6RouterControl:
1949 {
1950 std::bitset<8> control;
Johnathan Mantey65265362019-11-14 11:24:19 -08001951 EthernetInterface::DHCPConf dhcp =
1952 channelCall<getDHCPProperty>(channel);
1953 if ((dhcp == EthernetInterface::DHCPConf::both) ||
1954 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001955 {
1956 control[IPv6RouterControlFlag::Dynamic] = 1;
1957 }
1958 else
1959 {
1960 control[IPv6RouterControlFlag::Static] = 1;
1961 }
1962 ret.pack(control);
1963 return responseSuccess(std::move(ret));
1964 }
1965 case LanParam::IPv6StaticRouter1IP:
1966 {
1967 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001968 EthernetInterface::DHCPConf dhcp =
1969 channelCall<getDHCPProperty>(channel);
1970 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1971 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001972 {
1973 gateway =
1974 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1975 in6_addr{});
1976 }
1977 ret.pack(dataRef(gateway));
1978 return responseSuccess(std::move(ret));
1979 }
1980 case LanParam::IPv6StaticRouter1MAC:
1981 {
1982 ether_addr mac{};
1983 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1984 if (neighbor)
1985 {
1986 mac = neighbor->mac;
1987 }
1988 ret.pack(dataRef(mac));
1989 return responseSuccess(std::move(ret));
1990 }
1991 case LanParam::IPv6StaticRouter1PrefixLength:
1992 {
1993 ret.pack(UINT8_C(0));
1994 return responseSuccess(std::move(ret));
1995 }
1996 case LanParam::IPv6StaticRouter1PrefixValue:
1997 {
1998 in6_addr prefix{};
1999 ret.pack(dataRef(prefix));
2000 return responseSuccess(std::move(ret));
2001 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00002002 case LanParam::cipherSuitePrivilegeLevels:
2003 {
2004 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
2005
2006 uint8_t resp =
2007 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
2008 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
2009 if (!resp)
2010 {
2011 constexpr uint8_t reserved1 = 0x00;
2012 ret.pack(reserved1, csPrivilegeLevels);
2013 return responseSuccess(std::move(ret));
2014 }
2015 else
2016 {
2017 return response(resp);
2018 }
2019 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002020 }
2021
Johnathan Manteyb87034e2019-09-16 10:50:50 -07002022 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
2023 {
2024 return getLanOem(channel, parameter, set, block);
2025 }
2026
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002027 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002028}
2029
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002030} // namespace transport
2031} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302032
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002033void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302034
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002035void register_netfn_transport_functions()
2036{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002037 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2038 ipmi::transport::cmdSetLanConfigParameters,
2039 ipmi::Privilege::Admin, ipmi::transport::setLan);
2040 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2041 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08002042 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002043}