blob: c8dccb3c16bf4e5e7747dbbfbee3e216290f461b [file] [log] [blame]
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001#include "app/channel.hpp"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include <arpa/inet.h>
William A. Kennington IIIc514d872019-04-06 18:19:38 -07004#include <netinet/ether.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07005
William A. Kennington IIIc514d872019-04-06 18:19:38 -07006#include <array>
7#include <bitset>
8#include <cinttypes>
9#include <cstdint>
10#include <cstring>
Johnathan Manteyaffadb52019-10-07 10:13:53 -070011#include <fstream>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070012#include <functional>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070013#include <ipmid/api.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070014#include <ipmid/message.hpp>
15#include <ipmid/message/types.hpp>
16#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070017#include <ipmid/utils.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070018#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <phosphor-logging/elog-errors.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070020#include <phosphor-logging/elog.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070021#include <phosphor-logging/log.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070022#include <sdbusplus/bus.hpp>
23#include <sdbusplus/exception.hpp>
tomjose26e17732016-03-03 08:52:51 -060024#include <string>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070025#include <string_view>
26#include <type_traits>
27#include <unordered_map>
28#include <unordered_set>
29#include <user_channel/channel_layer.hpp>
30#include <utility>
31#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070032#include <xyz/openbmc_project/Common/error.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070033#include <xyz/openbmc_project/Network/IP/server.hpp>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070034#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070035
William A. Kennington IIIc514d872019-04-06 18:19:38 -070036using phosphor::logging::commit;
37using phosphor::logging::elog;
38using phosphor::logging::entry;
39using phosphor::logging::level;
40using phosphor::logging::log;
41using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
42using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070043using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070044
Johnathan Manteyaffadb52019-10-07 10:13:53 -070045namespace cipher
46{
47
48std::vector<uint8_t> getCipherList()
49{
50 std::vector<uint8_t> cipherList;
51
52 std::ifstream jsonFile(cipher::configFile);
53 if (!jsonFile.is_open())
54 {
55 log<level::ERR>("Channel Cipher suites file not found");
56 elog<InternalFailure>();
57 }
58
59 auto data = Json::parse(jsonFile, nullptr, false);
60 if (data.is_discarded())
61 {
62 log<level::ERR>("Parsing channel cipher suites JSON failed");
63 elog<InternalFailure>();
64 }
65
66 // Byte 1 is reserved
67 cipherList.push_back(0x00);
68
69 for (const auto& record : data)
70 {
71 cipherList.push_back(record.value(cipher, 0));
72 }
73
74 return cipherList;
75}
76} // namespace cipher
77
78namespace ipmi
79{
80namespace transport
81{
82
William A. Kennington IIIc514d872019-04-06 18:19:38 -070083// LAN Handler specific response codes
84constexpr Cc ccParamNotSupported = 0x80;
85constexpr Cc ccParamSetLocked = 0x81;
86constexpr Cc ccParamReadOnly = 0x82;
87
88// VLANs are a 12-bit value
89constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
90constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
91
William A. Kennington III16064aa2019-04-13 17:44:53 -070092// Arbitrary v6 Address Limits to prevent too much output in ipmitool
93constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
94constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
95
William A. Kennington IIIc514d872019-04-06 18:19:38 -070096// D-Bus Network Daemon definitions
97constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
98constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
99
100constexpr auto INTF_SYSTEMCONFIG =
101 "xyz.openbmc_project.Network.SystemConfiguration";
102constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
103constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
104constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
105constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700106constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
107constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
108 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700109constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
110constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
111
112/** @brief Generic paramters for different address families */
113template <int family>
114struct AddrFamily
115{
116};
117
118/** @brief Parameter specialization for IPv4 */
119template <>
120struct AddrFamily<AF_INET>
121{
122 using addr = in_addr;
123 static constexpr auto protocol = IP::Protocol::IPv4;
124 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
125 static constexpr uint8_t defaultPrefix = 32;
126 static constexpr char propertyGateway[] = "DefaultGateway";
127};
128
William A. Kennington III16064aa2019-04-13 17:44:53 -0700129/** @brief Parameter specialization for IPv6 */
130template <>
131struct AddrFamily<AF_INET6>
132{
133 using addr = in6_addr;
134 static constexpr auto protocol = IP::Protocol::IPv6;
135 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
136 static constexpr uint8_t defaultPrefix = 128;
137 static constexpr char propertyGateway[] = "DefaultGateway6";
138};
139
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700140/** @brief Valid address origins for IPv4 */
141const std::unordered_set<IP::AddressOrigin> originsV4 = {
142 IP::AddressOrigin::Static,
143 IP::AddressOrigin::DHCP,
144};
145
William A. Kennington III16064aa2019-04-13 17:44:53 -0700146/** @brief Valid address origins for IPv6 */
147const std::unordered_set<IP::AddressOrigin> originsV6Static = {
148 IP::AddressOrigin::Static};
149const std::unordered_set<IP::AddressOrigin> originsV6Dynamic = {
150 IP::AddressOrigin::DHCP,
151 IP::AddressOrigin::SLAAC,
152};
153
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700154/** @brief Interface IP Address configuration parameters */
155template <int family>
156struct IfAddr
157{
158 std::string path;
159 typename AddrFamily<family>::addr address;
160 IP::AddressOrigin origin;
161 uint8_t prefix;
162};
163
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700164/** @brief Interface Neighbor configuration parameters */
165template <int family>
166struct IfNeigh
167{
168 std::string path;
169 typename AddrFamily<family>::addr ip;
170 ether_addr mac;
171};
172
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700173/** @brief IPMI LAN Parameters */
174enum class LanParam : uint8_t
175{
176 SetStatus = 0,
177 AuthSupport = 1,
178 AuthEnables = 2,
179 IP = 3,
180 IPSrc = 4,
181 MAC = 5,
182 SubnetMask = 6,
183 Gateway1 = 12,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700184 Gateway1MAC = 13,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700185 VLANId = 20,
186 CiphersuiteSupport = 22,
187 CiphersuiteEntries = 23,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700188 IPFamilySupport = 50,
189 IPFamilyEnables = 51,
190 IPv6Status = 55,
191 IPv6StaticAddresses = 56,
192 IPv6DynamicAddresses = 59,
193 IPv6RouterControl = 64,
194 IPv6StaticRouter1IP = 65,
195 IPv6StaticRouter1MAC = 66,
196 IPv6StaticRouter1PrefixLength = 67,
197 IPv6StaticRouter1PrefixValue = 68,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700198};
199
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700200static constexpr uint8_t oemCmdStart = 192;
201static constexpr uint8_t oemCmdEnd = 255;
202
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700203/** @brief IPMI IP Origin Types */
204enum class IPSrc : uint8_t
205{
206 Unspecified = 0,
207 Static = 1,
208 DHCP = 2,
209 BIOS = 3,
210 BMC = 4,
211};
212
213/** @brief IPMI Set Status */
214enum class SetStatus : uint8_t
215{
216 Complete = 0,
217 InProgress = 1,
218 Commit = 2,
219};
220
William A. Kennington III16064aa2019-04-13 17:44:53 -0700221/** @brief IPMI Family Suport Bits */
222namespace IPFamilySupportFlag
223{
224constexpr uint8_t IPv6Only = 0;
225constexpr uint8_t DualStack = 1;
226constexpr uint8_t IPv6Alerts = 2;
227} // namespace IPFamilySupportFlag
228
229/** @brief IPMI IPFamily Enables Flag */
230enum class IPFamilyEnables : uint8_t
231{
232 IPv4Only = 0,
233 IPv6Only = 1,
234 DualStack = 2,
235};
236
237/** @brief IPMI IPv6 Dyanmic Status Bits */
238namespace IPv6StatusFlag
239{
240constexpr uint8_t DHCP = 0;
241constexpr uint8_t SLAAC = 1;
242}; // namespace IPv6StatusFlag
243
244/** @brief IPMI IPv6 Source */
245enum class IPv6Source : uint8_t
246{
247 Static = 0,
248 SLAAC = 1,
249 DHCP = 2,
250};
251
252/** @brief IPMI IPv6 Address Status */
253enum class IPv6AddressStatus : uint8_t
254{
255 Active = 0,
256 Disabled = 1,
257};
258
259namespace IPv6RouterControlFlag
260{
261constexpr uint8_t Static = 0;
262constexpr uint8_t Dynamic = 1;
263}; // namespace IPv6RouterControlFlag
264
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700265/** @brief A trivial helper used to determine if two PODs are equal
266 *
267 * @params[in] a - The first object to compare
268 * @params[in] b - The second object to compare
269 * @return True if the objects are the same bytewise
270 */
271template <typename T>
272bool equal(const T& a, const T& b)
273{
274 static_assert(std::is_trivially_copyable_v<T>);
275 return std::memcmp(&a, &b, sizeof(T)) == 0;
276}
277
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700278/** @brief Copies bytes from an array into a trivially copyable container
279 *
280 * @params[out] t - The container receiving the data
281 * @params[in] bytes - The data to copy
282 */
283template <size_t N, typename T>
284void copyInto(T& t, const std::array<uint8_t, N>& bytes)
285{
286 static_assert(std::is_trivially_copyable_v<T>);
287 static_assert(N == sizeof(T));
288 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800289}
290
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700291/** @brief Gets a generic view of the bytes in the input container
292 *
293 * @params[in] t - The data to reference
294 * @return A string_view referencing the bytes in the container
295 */
296template <typename T>
297std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600298{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700299 static_assert(std::is_trivially_copyable_v<T>);
300 return {reinterpret_cast<const char*>(&t), sizeof(T)};
301}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530302
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700303/** @brief The dbus parameters for the interface corresponding to a channel
304 * This helps reduce the number of mapper lookups we need for each
305 * query and simplifies finding the VLAN interface if needed.
306 */
307struct ChannelParams
308{
309 /** @brief The channel ID */
310 int id;
311 /** @brief channel name for the interface */
312 std::string ifname;
313 /** @brief Name of the service on the bus */
314 std::string service;
315 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
316 std::string ifPath;
317 /** @brief Logical adapter path used for address assignment */
318 std::string logicalPath;
319};
320
321/** @brief Determines the ethernet interface name corresponding to a channel
322 * Tries to map a VLAN object first so that the address information
323 * is accurate. Otherwise it gets the standard ethernet interface.
324 *
325 * @param[in] bus - The bus object used for lookups
326 * @param[in] channel - The channel id corresponding to an ethernet interface
327 * @return Ethernet interface service and object path if it exists
328 */
329std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
330 uint8_t channel)
331{
332 auto ifname = getChannelName(channel);
333 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800334 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700335 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800336 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800337
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700338 // Enumerate all VLAN + ETHERNET interfaces
339 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
340 "GetSubTree");
341 req.append(PATH_ROOT, 0,
342 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
343 auto reply = bus.call(req);
344 ObjectTree objs;
345 reply.read(objs);
346
347 ChannelParams params;
348 for (const auto& [path, impls] : objs)
349 {
350 if (path.find(ifname) == path.npos)
351 {
352 continue;
353 }
354 for (const auto& [service, intfs] : impls)
355 {
356 bool vlan = false;
357 bool ethernet = false;
358 for (const auto& intf : intfs)
359 {
360 if (intf == INTF_VLAN)
361 {
362 vlan = true;
363 }
364 else if (intf == INTF_ETHERNET)
365 {
366 ethernet = true;
367 }
368 }
369 if (params.service.empty() && (vlan || ethernet))
370 {
371 params.service = service;
372 }
373 if (params.ifPath.empty() && !vlan && ethernet)
374 {
375 params.ifPath = path;
376 }
377 if (params.logicalPath.empty() && vlan)
378 {
379 params.logicalPath = path;
380 }
381 }
382 }
383
384 // We must have a path for the underlying interface
385 if (params.ifPath.empty())
386 {
387 return std::nullopt;
388 }
389 // We don't have a VLAN so the logical path is the same
390 if (params.logicalPath.empty())
391 {
392 params.logicalPath = params.ifPath;
393 }
394
395 params.id = channel;
396 params.ifname = std::move(ifname);
397 return std::move(params);
398}
399
400/** @brief A trivial helper around maybeGetChannelParams() that throws an
401 * exception when it is unable to acquire parameters for the channel.
402 *
403 * @param[in] bus - The bus object used for lookups
404 * @param[in] channel - The channel id corresponding to an ethernet interface
405 * @return Ethernet interface service and object path
406 */
407ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
408{
409 auto params = maybeGetChannelParams(bus, channel);
410 if (!params)
411 {
412 log<level::ERR>("Failed to get channel params",
413 entry("CHANNEL=%" PRIu8, channel));
414 elog<InternalFailure>();
415 }
416 return std::move(*params);
417}
418
419/** @brief Wraps the phosphor logging method to insert some additional metadata
420 *
421 * @param[in] params - The parameters for the channel
422 * ...
423 */
424template <auto level, typename... Args>
425auto logWithChannel(const ChannelParams& params, Args&&... args)
426{
427 return log<level>(std::forward<Args>(args)...,
428 entry("CHANNEL=%d", params.id),
429 entry("IFNAME=%s", params.ifname.c_str()));
430}
431template <auto level, typename... Args>
432auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
433{
434 if (params)
435 {
436 return logWithChannel<level>(*params, std::forward<Args>(args)...);
437 }
438 return log<level>(std::forward<Args>(args)...);
439}
440
441/** @brief Trivializes using parameter getter functions by providing a bus
442 * and channel parameters automatically.
443 *
444 * @param[in] channel - The channel id corresponding to an ethernet interface
445 * ...
446 */
447template <auto func, typename... Args>
448auto channelCall(uint8_t channel, Args&&... args)
449{
450 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
451 auto params = getChannelParams(bus, channel);
452 return std::invoke(func, bus, params, std::forward<Args>(args)...);
453}
454
455/** @brief Determines if the ethernet interface is using DHCP
456 *
457 * @param[in] bus - The bus object used for lookups
458 * @param[in] params - The parameters for the channel
459 * @return True if DHCP is enabled, false otherwise
460 */
461bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
462{
463 return std::get<bool>(getDbusProperty(
464 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
465}
466
467/** @brief Sets the system value for DHCP on the given interface
468 *
469 * @param[in] bus - The bus object used for lookups
470 * @param[in] params - The parameters for the channel
471 * @param[in] on - Whether or not to enable DHCP
472 */
473void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
474 bool on)
475{
476 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
477 "DHCPEnabled", on);
478}
479
480/** @brief Converts a human readable MAC string into MAC bytes
481 *
482 * @param[in] mac - The MAC string
483 * @return MAC in bytes
484 */
485ether_addr stringToMAC(const char* mac)
486{
487 const ether_addr* ret = ether_aton(mac);
488 if (ret == nullptr)
489 {
490 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
491 elog<InternalFailure>();
492 }
493 return *ret;
494}
495
496/** @brief Determines the MAC of the ethernet interface
497 *
498 * @param[in] bus - The bus object used for lookups
499 * @param[in] params - The parameters for the channel
500 * @return The configured mac address
501 */
502ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
503{
504 auto macStr = std::get<std::string>(getDbusProperty(
505 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
506 return stringToMAC(macStr.c_str());
507}
508
509/** @brief Sets the system value for MAC address on the given interface
510 *
511 * @param[in] bus - The bus object used for lookups
512 * @param[in] params - The parameters for the channel
513 * @param[in] mac - MAC address to apply
514 */
515void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
516 const ether_addr& mac)
517{
518 std::string macStr = ether_ntoa(&mac);
519 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
520 macStr);
521}
522
523/** @brief Turns an IP address string into the network byte order form
524 * NOTE: This version strictly validates family matches
525 *
526 * @param[in] address - The string form of the address
527 * @return A network byte order address or none if conversion failed
528 */
529template <int family>
530std::optional<typename AddrFamily<family>::addr>
531 maybeStringToAddr(const char* address)
532{
533 typename AddrFamily<family>::addr ret;
534 if (inet_pton(family, address, &ret) == 1)
535 {
536 return ret;
537 }
538 return std::nullopt;
539}
540
541/** @brief Turns an IP address string into the network byte order form
542 * NOTE: This version strictly validates family matches
543 *
544 * @param[in] address - The string form of the address
545 * @return A network byte order address
546 */
547template <int family>
548typename AddrFamily<family>::addr stringToAddr(const char* address)
549{
550 auto ret = maybeStringToAddr<family>(address);
551 if (!ret)
552 {
553 log<level::ERR>("Failed to convert IP Address",
554 entry("FAMILY=%d", family),
555 entry("ADDRESS=%s", address));
556 elog<InternalFailure>();
557 }
558 return *ret;
559}
560
561/** @brief Turns an IP address in network byte order into a string
562 *
563 * @param[in] address - The string form of the address
564 * @return A network byte order address
565 */
566template <int family>
567std::string addrToString(const typename AddrFamily<family>::addr& address)
568{
569 std::string ret(AddrFamily<family>::maxStrLen, '\0');
570 inet_ntop(family, &address, ret.data(), ret.size());
571 ret.resize(strlen(ret.c_str()));
572 return ret;
573}
574
575/** @brief Retrieves the current gateway for the address family on the system
576 * NOTE: The gateway is currently system wide and not per channel
577 *
578 * @param[in] bus - The bus object used for lookups
579 * @param[in] params - The parameters for the channel
580 * @return An address representing the gateway address if it exists
581 */
582template <int family>
583std::optional<typename AddrFamily<family>::addr>
584 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
585{
586 auto gatewayStr = std::get<std::string>(getDbusProperty(
587 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
588 AddrFamily<family>::propertyGateway));
589 if (gatewayStr.empty())
590 {
591 return std::nullopt;
592 }
593 return stringToAddr<family>(gatewayStr.c_str());
594}
595
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700596/** @brief A lazy lookup mechanism for iterating over object properties stored
597 * in DBus. This will only perform the object lookup when needed, and
598 * retains a cache of previous lookups to speed up future iterations.
599 */
600class ObjectLookupCache
601{
602 public:
603 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
604
605 /** @brief Creates a new ObjectLookupCache for the interface on the bus
606 * NOTE: The inputs to this object must outlive the object since
607 * they are only referenced by it.
608 *
609 * @param[in] bus - The bus object used for lookups
610 * @param[in] params - The parameters for the channel
611 * @param[in] intf - The interface we are looking up
612 */
613 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
614 const char* intf) :
615 bus(bus),
616 params(params), intf(intf),
617 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
618 {
619 }
620
621 class iterator : public ObjectTree::const_iterator
622 {
623 public:
624 using value_type = PropertiesCache::value_type;
625
626 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
627 ObjectTree::const_iterator(it), container(container),
628 ret(container.cache.end())
629 {
630 }
631 value_type& operator*()
632 {
633 ret = container.get(ObjectTree::const_iterator::operator*().first);
634 return *ret;
635 }
636 value_type* operator->()
637 {
638 return &operator*();
639 }
640
641 private:
642 ObjectLookupCache& container;
643 PropertiesCache::iterator ret;
644 };
645
646 iterator begin() noexcept
647 {
648 return iterator(objs.begin(), *this);
649 }
650
651 iterator end() noexcept
652 {
653 return iterator(objs.end(), *this);
654 }
655
656 private:
657 sdbusplus::bus::bus& bus;
658 const ChannelParams& params;
659 const char* const intf;
660 const ObjectTree objs;
661 PropertiesCache cache;
662
663 /** @brief Gets a cached copy of the object properties if possible
664 * Otherwise performs a query on DBus to look them up
665 *
666 * @param[in] path - The object path to lookup
667 * @return An iterator for the specified object path + properties
668 */
669 PropertiesCache::iterator get(const std::string& path)
670 {
671 auto it = cache.find(path);
672 if (it != cache.end())
673 {
674 return it;
675 }
676 auto properties = getAllDbusProperties(bus, params.service, path, intf);
677 return cache.insert({path, std::move(properties)}).first;
678 }
679};
680
681/** @brief Searches the ip object lookup cache for an address matching
682 * the input parameters. NOTE: The index lacks stability across address
683 * changes since the network daemon has no notion of stable indicies.
684 *
685 * @param[in] bus - The bus object used for lookups
686 * @param[in] params - The parameters for the channel
687 * @param[in] idx - The index of the desired address on the interface
688 * @param[in] origins - The allowed origins for the address objects
689 * @param[in] ips - The object lookup cache holding all of the address info
690 * @return The address and prefix if it was found
691 */
692template <int family>
693std::optional<IfAddr<family>>
694 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
695 uint8_t idx,
696 const std::unordered_set<IP::AddressOrigin>& origins,
697 ObjectLookupCache& ips)
698{
699 for (const auto& [path, properties] : ips)
700 {
701 const auto& addrStr = std::get<std::string>(properties.at("Address"));
702 auto addr = maybeStringToAddr<family>(addrStr.c_str());
703 if (!addr)
704 {
705 continue;
706 }
707
708 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
709 std::get<std::string>(properties.at("Origin")));
710 if (origins.find(origin) == origins.end())
711 {
712 continue;
713 }
714
715 if (idx > 0)
716 {
717 idx--;
718 continue;
719 }
720
721 IfAddr<family> ifaddr;
722 ifaddr.path = path;
723 ifaddr.address = *addr;
724 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
725 ifaddr.origin = origin;
726 return std::move(ifaddr);
727 }
728
729 return std::nullopt;
730}
731
732/** @brief Trivial helper around findIfAddr that simplifies calls
733 * for one off lookups. Don't use this if you intend to do multiple
734 * lookups at a time.
735 *
736 * @param[in] bus - The bus object used for lookups
737 * @param[in] params - The parameters for the channel
738 * @param[in] idx - The index of the desired address on the interface
739 * @param[in] origins - The allowed origins for the address objects
740 * @return The address and prefix if it was found
741 */
742template <int family>
743auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
744 uint8_t idx,
745 const std::unordered_set<IP::AddressOrigin>& origins)
746{
747 ObjectLookupCache ips(bus, params, INTF_IP);
748 return findIfAddr<family>(bus, params, idx, origins, ips);
749}
750
751/** @brief Deletes the dbus object. Ignores empty objects or objects that are
752 * missing from the bus.
753 *
754 * @param[in] bus - The bus object used for lookups
755 * @param[in] service - The name of the service
756 * @param[in] path - The path of the object to delete
757 */
758void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
759 const std::string& path)
760{
761 if (path.empty())
762 {
763 return;
764 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530765 try
tomjose26e17732016-03-03 08:52:51 -0600766 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700767 auto req = bus.new_method_call(service.c_str(), path.c_str(),
768 ipmi::DELETE_INTERFACE, "Delete");
769 bus.call_noreply(req);
770 }
771 catch (const sdbusplus::exception::SdBusError& e)
772 {
773 if (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
1116 setDHCPProperty(bus, params, 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 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001169 auto 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
1178 setDHCPProperty(bus, params, dhcp);
1179 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}
1316
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001317RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
1318 message::Payload& req)
1319{
1320 auto channel = static_cast<uint8_t>(channelBits);
1321 if (!doesDeviceExist(channel))
1322 {
1323 req.trailingOk = true;
1324 return responseInvalidFieldRequest();
1325 }
1326
1327 switch (static_cast<LanParam>(parameter))
1328 {
1329 case LanParam::SetStatus:
1330 {
1331 uint2_t flag;
1332 uint6_t rsvd;
1333 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1334 {
1335 return responseReqDataLenInvalid();
1336 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001337 if (rsvd)
1338 {
1339 return responseInvalidFieldRequest();
1340 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001341 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1342 switch (status)
1343 {
1344 case SetStatus::Complete:
1345 {
1346 getSetStatus(channel) = status;
1347 return responseSuccess();
1348 }
1349 case SetStatus::InProgress:
1350 {
1351 auto& storedStatus = getSetStatus(channel);
1352 if (storedStatus == SetStatus::InProgress)
1353 {
1354 return response(ccParamSetLocked);
1355 }
1356 storedStatus = status;
1357 return responseSuccess();
1358 }
1359 case SetStatus::Commit:
1360 if (getSetStatus(channel) != SetStatus::InProgress)
1361 {
1362 return responseInvalidFieldRequest();
1363 }
1364 return responseSuccess();
1365 }
1366 return response(ccParamNotSupported);
1367 }
1368 case LanParam::AuthSupport:
1369 {
1370 req.trailingOk = true;
1371 return response(ccParamReadOnly);
1372 }
1373 case LanParam::AuthEnables:
1374 {
1375 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001376 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001377 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001378 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001379 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001380 in_addr ip;
1381 std::array<uint8_t, sizeof(ip)> bytes;
1382 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1383 {
1384 return responseReqDataLenInvalid();
1385 }
1386 copyInto(ip, bytes);
1387 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1388 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301389 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001390 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301391 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001392 uint4_t flag;
1393 uint4_t rsvd;
1394 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1395 {
1396 return responseReqDataLenInvalid();
1397 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001398 if (rsvd)
1399 {
1400 return responseInvalidFieldRequest();
1401 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001402 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1403 {
1404 case IPSrc::DHCP:
1405 {
1406 channelCall<setDHCPProperty>(channel, true);
1407 return responseSuccess();
1408 }
1409 case IPSrc::Unspecified:
1410 case IPSrc::Static:
1411 case IPSrc::BIOS:
1412 case IPSrc::BMC:
1413 {
1414 channelCall<setDHCPProperty>(channel, false);
1415 return responseSuccess();
1416 }
1417 }
1418 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301419 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001420 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301421 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001422 ether_addr mac;
1423 std::array<uint8_t, sizeof(mac)> bytes;
1424 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301425 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001426 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301427 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001428 copyInto(mac, bytes);
1429 channelCall<setMACProperty>(channel, mac);
1430 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301431 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001432 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301433 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001434 in_addr netmask;
1435 std::array<uint8_t, sizeof(netmask)> bytes;
1436 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301437 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001438 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301439 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001440 copyInto(netmask, bytes);
1441 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1442 netmaskToPrefix(netmask));
1443 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301444 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001445 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301446 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001447 in_addr gateway;
1448 std::array<uint8_t, sizeof(gateway)> bytes;
1449 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1450 {
1451 return responseReqDataLenInvalid();
1452 }
1453 copyInto(gateway, bytes);
1454 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1455 return responseSuccess();
1456 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001457 case LanParam::Gateway1MAC:
1458 {
1459 ether_addr gatewayMAC;
1460 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1461 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1462 {
1463 return responseReqDataLenInvalid();
1464 }
1465 copyInto(gatewayMAC, bytes);
1466 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1467 return responseSuccess();
1468 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001469 case LanParam::VLANId:
1470 {
1471 uint16_t vlanData;
1472 if (req.unpack(vlanData) != 0 || !req.fullyUnpacked())
1473 {
1474 return responseReqDataLenInvalid();
1475 }
1476 if ((vlanData & VLAN_ENABLE_FLAG) == 0)
1477 {
1478 lastDisabledVlan[channel] = vlanData & VLAN_VALUE_MASK;
1479 vlanData = 0;
1480 }
1481 channelCall<reconfigureVLAN>(channel, vlanData & VLAN_VALUE_MASK);
1482 return responseSuccess();
1483 }
1484 case LanParam::CiphersuiteSupport:
1485 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001486 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001487 {
1488 req.trailingOk = true;
1489 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301490 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001491 case LanParam::IPFamilyEnables:
1492 {
1493 uint8_t enables;
1494 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1495 {
1496 return responseReqDataLenInvalid();
1497 }
1498 switch (static_cast<IPFamilyEnables>(enables))
1499 {
1500 case IPFamilyEnables::DualStack:
1501 return responseSuccess();
1502 case IPFamilyEnables::IPv4Only:
1503 case IPFamilyEnables::IPv6Only:
1504 return response(ccParamNotSupported);
1505 }
1506 return response(ccParamNotSupported);
1507 }
1508 case LanParam::IPv6Status:
1509 {
1510 req.trailingOk = true;
1511 return response(ccParamReadOnly);
1512 }
1513 case LanParam::IPv6StaticAddresses:
1514 {
1515 uint8_t set;
1516 uint7_t rsvd;
1517 bool enabled;
1518 in6_addr ip;
1519 std::array<uint8_t, sizeof(ip)> ipbytes;
1520 uint8_t prefix;
1521 uint8_t status;
1522 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1523 !req.fullyUnpacked())
1524 {
1525 return responseReqDataLenInvalid();
1526 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001527 if (rsvd)
1528 {
1529 return responseInvalidFieldRequest();
1530 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001531 copyInto(ip, ipbytes);
1532 if (enabled)
1533 {
1534 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1535 }
1536 else
1537 {
1538 channelCall<deconfigureIfAddr6>(channel, set);
1539 }
1540 return responseSuccess();
1541 }
1542 case LanParam::IPv6DynamicAddresses:
1543 {
1544 req.trailingOk = true;
1545 return response(ccParamReadOnly);
1546 }
1547 case LanParam::IPv6RouterControl:
1548 {
1549 std::bitset<8> control;
1550 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1551 {
1552 return responseReqDataLenInvalid();
1553 }
1554 std::bitset<8> expected;
1555 if (channelCall<getDHCPProperty>(channel))
1556 {
1557 expected[IPv6RouterControlFlag::Dynamic] = 1;
1558 }
1559 else
1560 {
1561 expected[IPv6RouterControlFlag::Static] = 1;
1562 }
1563 if (expected != control)
1564 {
1565 return responseInvalidFieldRequest();
1566 }
1567 return responseSuccess();
1568 }
1569 case LanParam::IPv6StaticRouter1IP:
1570 {
1571 in6_addr gateway;
1572 std::array<uint8_t, sizeof(gateway)> bytes;
1573 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1574 {
1575 return responseReqDataLenInvalid();
1576 }
1577 copyInto(gateway, bytes);
1578 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1579 return responseSuccess();
1580 }
1581 case LanParam::IPv6StaticRouter1MAC:
1582 {
1583 ether_addr mac;
1584 std::array<uint8_t, sizeof(mac)> bytes;
1585 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1586 {
1587 return responseReqDataLenInvalid();
1588 }
1589 copyInto(mac, bytes);
1590 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1591 return responseSuccess();
1592 }
1593 case LanParam::IPv6StaticRouter1PrefixLength:
1594 {
1595 uint8_t prefix;
1596 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1597 {
1598 return responseReqDataLenInvalid();
1599 }
1600 if (prefix != 0)
1601 {
1602 return responseInvalidFieldRequest();
1603 }
1604 return responseSuccess();
1605 }
1606 case LanParam::IPv6StaticRouter1PrefixValue:
1607 {
1608 std::array<uint8_t, sizeof(in6_addr)> bytes;
1609 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1610 {
1611 return responseReqDataLenInvalid();
1612 }
1613 // Accept any prefix value since our prefix length has to be 0
1614 return responseSuccess();
1615 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301616 }
vishwa1eaea4f2016-02-26 11:57:40 -06001617
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001618 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1619 {
1620 return setLanOem(channel, parameter, req);
1621 }
1622
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001623 req.trailingOk = true;
1624 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001625}
1626
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001627RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
1628 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301629{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001630 message::Payload ret;
1631 constexpr uint8_t current_revision = 0x11;
1632 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001633
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001634 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301635 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001636 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301637 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001638
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001639 auto channel = static_cast<uint8_t>(channelBits);
1640 if (!doesDeviceExist(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001641 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001642 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001643 }
1644
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001645 static std::vector<uint8_t> cipherList;
1646 static bool listInit = false;
1647 if (!listInit)
1648 {
1649 try
1650 {
1651 cipherList = cipher::getCipherList();
1652 listInit = true;
1653 }
1654 catch (const std::exception& e)
1655 {
1656 }
1657 }
1658
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001659 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301660 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001661 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301662 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001663 SetStatus status;
1664 try
1665 {
1666 status = setStatus.at(channel);
1667 }
1668 catch (const std::out_of_range&)
1669 {
1670 status = SetStatus::Complete;
1671 }
1672 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1673 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301674 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001675 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301676 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001677 std::bitset<6> support;
1678 ret.pack(support, uint2_t{});
1679 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301680 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001681 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001682 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001683 std::bitset<6> enables;
1684 ret.pack(enables, uint2_t{}); // Callback
1685 ret.pack(enables, uint2_t{}); // User
1686 ret.pack(enables, uint2_t{}); // Operator
1687 ret.pack(enables, uint2_t{}); // Admin
1688 ret.pack(enables, uint2_t{}); // OEM
1689 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001690 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001691 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001692 {
1693 auto ifaddr = channelCall<getIfAddr4>(channel);
1694 in_addr addr{};
1695 if (ifaddr)
1696 {
1697 addr = ifaddr->address;
1698 }
1699 ret.pack(dataRef(addr));
1700 return responseSuccess(std::move(ret));
1701 }
1702 case LanParam::IPSrc:
1703 {
1704 auto src = IPSrc::Static;
1705 if (channelCall<getDHCPProperty>(channel))
1706 {
1707 src = IPSrc::DHCP;
1708 }
1709 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1710 return responseSuccess(std::move(ret));
1711 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001712 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001713 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001714 ether_addr mac = channelCall<getMACProperty>(channel);
1715 ret.pack(dataRef(mac));
1716 return responseSuccess(std::move(ret));
1717 }
1718 case LanParam::SubnetMask:
1719 {
1720 auto ifaddr = channelCall<getIfAddr4>(channel);
1721 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1722 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301723 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001724 prefix = ifaddr->prefix;
1725 }
1726 in_addr netmask = prefixToNetmask(prefix);
1727 ret.pack(dataRef(netmask));
1728 return responseSuccess(std::move(ret));
1729 }
1730 case LanParam::Gateway1:
1731 {
1732 auto gateway =
1733 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1734 in_addr{});
1735 ret.pack(dataRef(gateway));
1736 return responseSuccess(std::move(ret));
1737 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001738 case LanParam::Gateway1MAC:
1739 {
1740 ether_addr mac{};
1741 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1742 if (neighbor)
1743 {
1744 mac = neighbor->mac;
1745 }
1746 ret.pack(dataRef(mac));
1747 return responseSuccess(std::move(ret));
1748 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001749 case LanParam::VLANId:
1750 {
1751 uint16_t vlan = channelCall<getVLANProperty>(channel);
1752 if (vlan != 0)
1753 {
1754 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301755 }
1756 else
1757 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001758 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301759 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001760 ret.pack(vlan);
1761 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001762 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001763 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001764 {
1765 if (!listInit)
1766 {
1767 return responseUnspecifiedError();
1768 }
1769 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1770 return responseSuccess(std::move(ret));
1771 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001772 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001773 {
1774 if (!listInit)
1775 {
1776 return responseUnspecifiedError();
1777 }
1778 ret.pack(cipherList);
1779 return responseSuccess(std::move(ret));
1780 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001781 case LanParam::IPFamilySupport:
1782 {
1783 std::bitset<8> support;
1784 support[IPFamilySupportFlag::IPv6Only] = 0;
1785 support[IPFamilySupportFlag::DualStack] = 1;
1786 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1787 ret.pack(support);
1788 return responseSuccess(std::move(ret));
1789 }
1790 case LanParam::IPFamilyEnables:
1791 {
1792 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1793 return responseSuccess(std::move(ret));
1794 }
1795 case LanParam::IPv6Status:
1796 {
1797 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1798 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1799 std::bitset<8> support;
1800 support[IPv6StatusFlag::DHCP] = 1;
1801 support[IPv6StatusFlag::SLAAC] = 1;
1802 ret.pack(support);
1803 return responseSuccess(std::move(ret));
1804 }
1805 case LanParam::IPv6StaticAddresses:
1806 {
1807 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1808 {
1809 return responseParmOutOfRange();
1810 }
1811 getLanIPv6Address(ret, channel, set, originsV6Static);
1812 return responseSuccess(std::move(ret));
1813 }
1814 case LanParam::IPv6DynamicAddresses:
1815 {
1816 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1817 {
1818 return responseParmOutOfRange();
1819 }
1820 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1821 return responseSuccess(std::move(ret));
1822 }
1823 case LanParam::IPv6RouterControl:
1824 {
1825 std::bitset<8> control;
1826 if (channelCall<getDHCPProperty>(channel))
1827 {
1828 control[IPv6RouterControlFlag::Dynamic] = 1;
1829 }
1830 else
1831 {
1832 control[IPv6RouterControlFlag::Static] = 1;
1833 }
1834 ret.pack(control);
1835 return responseSuccess(std::move(ret));
1836 }
1837 case LanParam::IPv6StaticRouter1IP:
1838 {
1839 in6_addr gateway{};
1840 if (!channelCall<getDHCPProperty>(channel))
1841 {
1842 gateway =
1843 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1844 in6_addr{});
1845 }
1846 ret.pack(dataRef(gateway));
1847 return responseSuccess(std::move(ret));
1848 }
1849 case LanParam::IPv6StaticRouter1MAC:
1850 {
1851 ether_addr mac{};
1852 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1853 if (neighbor)
1854 {
1855 mac = neighbor->mac;
1856 }
1857 ret.pack(dataRef(mac));
1858 return responseSuccess(std::move(ret));
1859 }
1860 case LanParam::IPv6StaticRouter1PrefixLength:
1861 {
1862 ret.pack(UINT8_C(0));
1863 return responseSuccess(std::move(ret));
1864 }
1865 case LanParam::IPv6StaticRouter1PrefixValue:
1866 {
1867 in6_addr prefix{};
1868 ret.pack(dataRef(prefix));
1869 return responseSuccess(std::move(ret));
1870 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001871 }
1872
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001873 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1874 {
1875 return getLanOem(channel, parameter, set, block);
1876 }
1877
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001878 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001879}
1880
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001881} // namespace transport
1882} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301883
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001884void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301885
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001886void register_netfn_transport_functions()
1887{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001888 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1889 ipmi::transport::cmdSetLanConfigParameters,
1890 ipmi::Privilege::Admin, ipmi::transport::setLan);
1891 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1892 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001893 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001894}