blob: e1126689ff06fd7e845504ecb40fb29d09009f86 [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}
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
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001341RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
1342 message::Payload& req)
1343{
1344 auto channel = static_cast<uint8_t>(channelBits);
1345 if (!doesDeviceExist(channel))
1346 {
1347 req.trailingOk = true;
1348 return responseInvalidFieldRequest();
1349 }
1350
1351 switch (static_cast<LanParam>(parameter))
1352 {
1353 case LanParam::SetStatus:
1354 {
1355 uint2_t flag;
1356 uint6_t rsvd;
1357 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1358 {
1359 return responseReqDataLenInvalid();
1360 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001361 if (rsvd)
1362 {
1363 return responseInvalidFieldRequest();
1364 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001365 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1366 switch (status)
1367 {
1368 case SetStatus::Complete:
1369 {
1370 getSetStatus(channel) = status;
1371 return responseSuccess();
1372 }
1373 case SetStatus::InProgress:
1374 {
1375 auto& storedStatus = getSetStatus(channel);
1376 if (storedStatus == SetStatus::InProgress)
1377 {
1378 return response(ccParamSetLocked);
1379 }
1380 storedStatus = status;
1381 return responseSuccess();
1382 }
1383 case SetStatus::Commit:
1384 if (getSetStatus(channel) != SetStatus::InProgress)
1385 {
1386 return responseInvalidFieldRequest();
1387 }
1388 return responseSuccess();
1389 }
1390 return response(ccParamNotSupported);
1391 }
1392 case LanParam::AuthSupport:
1393 {
1394 req.trailingOk = true;
1395 return response(ccParamReadOnly);
1396 }
1397 case LanParam::AuthEnables:
1398 {
1399 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001400 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001401 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001402 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001403 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001404 in_addr ip;
1405 std::array<uint8_t, sizeof(ip)> bytes;
1406 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1407 {
1408 return responseReqDataLenInvalid();
1409 }
1410 copyInto(ip, bytes);
1411 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1412 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301413 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001414 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301415 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001416 uint4_t flag;
1417 uint4_t rsvd;
1418 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1419 {
1420 return responseReqDataLenInvalid();
1421 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001422 if (rsvd)
1423 {
1424 return responseInvalidFieldRequest();
1425 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001426 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1427 {
1428 case IPSrc::DHCP:
1429 {
1430 channelCall<setDHCPProperty>(channel, true);
1431 return responseSuccess();
1432 }
1433 case IPSrc::Unspecified:
1434 case IPSrc::Static:
1435 case IPSrc::BIOS:
1436 case IPSrc::BMC:
1437 {
1438 channelCall<setDHCPProperty>(channel, false);
1439 return responseSuccess();
1440 }
1441 }
1442 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301443 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001444 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301445 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001446 ether_addr mac;
1447 std::array<uint8_t, sizeof(mac)> bytes;
1448 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301449 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001450 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301451 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001452 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301453
1454 if (!isValidMACAddress(mac))
1455 {
1456 return responseInvalidFieldRequest();
1457 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001458 channelCall<setMACProperty>(channel, mac);
1459 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301460 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001461 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301462 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001463 in_addr netmask;
1464 std::array<uint8_t, sizeof(netmask)> bytes;
1465 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301466 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001467 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301468 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001469 copyInto(netmask, bytes);
1470 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1471 netmaskToPrefix(netmask));
1472 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301473 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001474 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301475 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001476 in_addr gateway;
1477 std::array<uint8_t, sizeof(gateway)> bytes;
1478 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1479 {
1480 return responseReqDataLenInvalid();
1481 }
1482 copyInto(gateway, bytes);
1483 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1484 return responseSuccess();
1485 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001486 case LanParam::Gateway1MAC:
1487 {
1488 ether_addr gatewayMAC;
1489 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1490 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1491 {
1492 return responseReqDataLenInvalid();
1493 }
1494 copyInto(gatewayMAC, bytes);
1495 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1496 return responseSuccess();
1497 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001498 case LanParam::VLANId:
1499 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301500 uint12_t vlanData = 0;
1501 uint3_t reserved = 0;
1502 bool vlanEnable = 0;
1503
1504 if (req.unpack(vlanData) || req.unpack(reserved) ||
1505 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001506 {
1507 return responseReqDataLenInvalid();
1508 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301509
1510 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001511 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301512 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001513 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301514
1515 uint16_t vlan = static_cast<uint16_t>(vlanData);
1516
1517 if (!vlanEnable)
1518 {
1519 lastDisabledVlan[channel] = vlan;
1520 vlan = 0;
1521 }
1522 channelCall<reconfigureVLAN>(channel, vlan);
1523
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001524 return responseSuccess();
1525 }
1526 case LanParam::CiphersuiteSupport:
1527 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001528 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001529 {
1530 req.trailingOk = true;
1531 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301532 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001533 case LanParam::IPFamilyEnables:
1534 {
1535 uint8_t enables;
1536 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1537 {
1538 return responseReqDataLenInvalid();
1539 }
1540 switch (static_cast<IPFamilyEnables>(enables))
1541 {
1542 case IPFamilyEnables::DualStack:
1543 return responseSuccess();
1544 case IPFamilyEnables::IPv4Only:
1545 case IPFamilyEnables::IPv6Only:
1546 return response(ccParamNotSupported);
1547 }
1548 return response(ccParamNotSupported);
1549 }
1550 case LanParam::IPv6Status:
1551 {
1552 req.trailingOk = true;
1553 return response(ccParamReadOnly);
1554 }
1555 case LanParam::IPv6StaticAddresses:
1556 {
1557 uint8_t set;
1558 uint7_t rsvd;
1559 bool enabled;
1560 in6_addr ip;
1561 std::array<uint8_t, sizeof(ip)> ipbytes;
1562 uint8_t prefix;
1563 uint8_t status;
1564 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1565 !req.fullyUnpacked())
1566 {
1567 return responseReqDataLenInvalid();
1568 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001569 if (rsvd)
1570 {
1571 return responseInvalidFieldRequest();
1572 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001573 copyInto(ip, ipbytes);
1574 if (enabled)
1575 {
1576 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1577 }
1578 else
1579 {
1580 channelCall<deconfigureIfAddr6>(channel, set);
1581 }
1582 return responseSuccess();
1583 }
1584 case LanParam::IPv6DynamicAddresses:
1585 {
1586 req.trailingOk = true;
1587 return response(ccParamReadOnly);
1588 }
1589 case LanParam::IPv6RouterControl:
1590 {
1591 std::bitset<8> control;
1592 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1593 {
1594 return responseReqDataLenInvalid();
1595 }
1596 std::bitset<8> expected;
1597 if (channelCall<getDHCPProperty>(channel))
1598 {
1599 expected[IPv6RouterControlFlag::Dynamic] = 1;
1600 }
1601 else
1602 {
1603 expected[IPv6RouterControlFlag::Static] = 1;
1604 }
1605 if (expected != control)
1606 {
1607 return responseInvalidFieldRequest();
1608 }
1609 return responseSuccess();
1610 }
1611 case LanParam::IPv6StaticRouter1IP:
1612 {
1613 in6_addr gateway;
1614 std::array<uint8_t, sizeof(gateway)> bytes;
1615 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1616 {
1617 return responseReqDataLenInvalid();
1618 }
1619 copyInto(gateway, bytes);
1620 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1621 return responseSuccess();
1622 }
1623 case LanParam::IPv6StaticRouter1MAC:
1624 {
1625 ether_addr mac;
1626 std::array<uint8_t, sizeof(mac)> bytes;
1627 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1628 {
1629 return responseReqDataLenInvalid();
1630 }
1631 copyInto(mac, bytes);
1632 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1633 return responseSuccess();
1634 }
1635 case LanParam::IPv6StaticRouter1PrefixLength:
1636 {
1637 uint8_t prefix;
1638 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1639 {
1640 return responseReqDataLenInvalid();
1641 }
1642 if (prefix != 0)
1643 {
1644 return responseInvalidFieldRequest();
1645 }
1646 return responseSuccess();
1647 }
1648 case LanParam::IPv6StaticRouter1PrefixValue:
1649 {
1650 std::array<uint8_t, sizeof(in6_addr)> bytes;
1651 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1652 {
1653 return responseReqDataLenInvalid();
1654 }
1655 // Accept any prefix value since our prefix length has to be 0
1656 return responseSuccess();
1657 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301658 }
vishwa1eaea4f2016-02-26 11:57:40 -06001659
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001660 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1661 {
1662 return setLanOem(channel, parameter, req);
1663 }
1664
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001665 req.trailingOk = true;
1666 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001667}
1668
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001669RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
1670 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301671{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001672 message::Payload ret;
1673 constexpr uint8_t current_revision = 0x11;
1674 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001675
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001676 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301677 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001678 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301679 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001680
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001681 auto channel = static_cast<uint8_t>(channelBits);
1682 if (!doesDeviceExist(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001683 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001684 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001685 }
1686
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001687 static std::vector<uint8_t> cipherList;
1688 static bool listInit = false;
1689 if (!listInit)
1690 {
1691 try
1692 {
1693 cipherList = cipher::getCipherList();
1694 listInit = true;
1695 }
1696 catch (const std::exception& e)
1697 {
1698 }
1699 }
1700
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001701 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301702 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001703 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301704 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001705 SetStatus status;
1706 try
1707 {
1708 status = setStatus.at(channel);
1709 }
1710 catch (const std::out_of_range&)
1711 {
1712 status = SetStatus::Complete;
1713 }
1714 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1715 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301716 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001717 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301718 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001719 std::bitset<6> support;
1720 ret.pack(support, uint2_t{});
1721 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301722 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001723 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001724 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001725 std::bitset<6> enables;
1726 ret.pack(enables, uint2_t{}); // Callback
1727 ret.pack(enables, uint2_t{}); // User
1728 ret.pack(enables, uint2_t{}); // Operator
1729 ret.pack(enables, uint2_t{}); // Admin
1730 ret.pack(enables, uint2_t{}); // OEM
1731 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001732 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001733 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001734 {
1735 auto ifaddr = channelCall<getIfAddr4>(channel);
1736 in_addr addr{};
1737 if (ifaddr)
1738 {
1739 addr = ifaddr->address;
1740 }
1741 ret.pack(dataRef(addr));
1742 return responseSuccess(std::move(ret));
1743 }
1744 case LanParam::IPSrc:
1745 {
1746 auto src = IPSrc::Static;
1747 if (channelCall<getDHCPProperty>(channel))
1748 {
1749 src = IPSrc::DHCP;
1750 }
1751 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1752 return responseSuccess(std::move(ret));
1753 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001754 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001755 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001756 ether_addr mac = channelCall<getMACProperty>(channel);
1757 ret.pack(dataRef(mac));
1758 return responseSuccess(std::move(ret));
1759 }
1760 case LanParam::SubnetMask:
1761 {
1762 auto ifaddr = channelCall<getIfAddr4>(channel);
1763 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1764 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301765 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001766 prefix = ifaddr->prefix;
1767 }
1768 in_addr netmask = prefixToNetmask(prefix);
1769 ret.pack(dataRef(netmask));
1770 return responseSuccess(std::move(ret));
1771 }
1772 case LanParam::Gateway1:
1773 {
1774 auto gateway =
1775 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1776 in_addr{});
1777 ret.pack(dataRef(gateway));
1778 return responseSuccess(std::move(ret));
1779 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001780 case LanParam::Gateway1MAC:
1781 {
1782 ether_addr mac{};
1783 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1784 if (neighbor)
1785 {
1786 mac = neighbor->mac;
1787 }
1788 ret.pack(dataRef(mac));
1789 return responseSuccess(std::move(ret));
1790 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001791 case LanParam::VLANId:
1792 {
1793 uint16_t vlan = channelCall<getVLANProperty>(channel);
1794 if (vlan != 0)
1795 {
1796 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301797 }
1798 else
1799 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001800 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301801 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001802 ret.pack(vlan);
1803 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001804 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001805 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001806 {
1807 if (!listInit)
1808 {
1809 return responseUnspecifiedError();
1810 }
1811 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1812 return responseSuccess(std::move(ret));
1813 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001814 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001815 {
1816 if (!listInit)
1817 {
1818 return responseUnspecifiedError();
1819 }
1820 ret.pack(cipherList);
1821 return responseSuccess(std::move(ret));
1822 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001823 case LanParam::IPFamilySupport:
1824 {
1825 std::bitset<8> support;
1826 support[IPFamilySupportFlag::IPv6Only] = 0;
1827 support[IPFamilySupportFlag::DualStack] = 1;
1828 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1829 ret.pack(support);
1830 return responseSuccess(std::move(ret));
1831 }
1832 case LanParam::IPFamilyEnables:
1833 {
1834 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1835 return responseSuccess(std::move(ret));
1836 }
1837 case LanParam::IPv6Status:
1838 {
1839 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1840 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1841 std::bitset<8> support;
1842 support[IPv6StatusFlag::DHCP] = 1;
1843 support[IPv6StatusFlag::SLAAC] = 1;
1844 ret.pack(support);
1845 return responseSuccess(std::move(ret));
1846 }
1847 case LanParam::IPv6StaticAddresses:
1848 {
1849 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1850 {
1851 return responseParmOutOfRange();
1852 }
1853 getLanIPv6Address(ret, channel, set, originsV6Static);
1854 return responseSuccess(std::move(ret));
1855 }
1856 case LanParam::IPv6DynamicAddresses:
1857 {
1858 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1859 {
1860 return responseParmOutOfRange();
1861 }
1862 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1863 return responseSuccess(std::move(ret));
1864 }
1865 case LanParam::IPv6RouterControl:
1866 {
1867 std::bitset<8> control;
1868 if (channelCall<getDHCPProperty>(channel))
1869 {
1870 control[IPv6RouterControlFlag::Dynamic] = 1;
1871 }
1872 else
1873 {
1874 control[IPv6RouterControlFlag::Static] = 1;
1875 }
1876 ret.pack(control);
1877 return responseSuccess(std::move(ret));
1878 }
1879 case LanParam::IPv6StaticRouter1IP:
1880 {
1881 in6_addr gateway{};
1882 if (!channelCall<getDHCPProperty>(channel))
1883 {
1884 gateway =
1885 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1886 in6_addr{});
1887 }
1888 ret.pack(dataRef(gateway));
1889 return responseSuccess(std::move(ret));
1890 }
1891 case LanParam::IPv6StaticRouter1MAC:
1892 {
1893 ether_addr mac{};
1894 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1895 if (neighbor)
1896 {
1897 mac = neighbor->mac;
1898 }
1899 ret.pack(dataRef(mac));
1900 return responseSuccess(std::move(ret));
1901 }
1902 case LanParam::IPv6StaticRouter1PrefixLength:
1903 {
1904 ret.pack(UINT8_C(0));
1905 return responseSuccess(std::move(ret));
1906 }
1907 case LanParam::IPv6StaticRouter1PrefixValue:
1908 {
1909 in6_addr prefix{};
1910 ret.pack(dataRef(prefix));
1911 return responseSuccess(std::move(ret));
1912 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001913 }
1914
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001915 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1916 {
1917 return getLanOem(channel, parameter, set, block);
1918 }
1919
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001920 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001921}
1922
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001923} // namespace transport
1924} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301925
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001926void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301927
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001928void register_netfn_transport_functions()
1929{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001930 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1931 ipmi::transport::cmdSetLanConfigParameters,
1932 ipmi::Privilege::Admin, ipmi::transport::setLan);
1933 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1934 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001935 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001936}