blob: 4479489e58770b85d5a794364619b76f05947bfb [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
vijayabharathix shettycc769252020-02-27 17:52:20 +00001341RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1342 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001343{
vijayabharathix shettycc769252020-02-27 17:52:20 +00001344 const uint8_t channel = convertCurrentChannelNum(
1345 static_cast<uint8_t>(channelBits), ctx->channel);
1346 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001347 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001348 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001349 req.trailingOk = true;
1350 return responseInvalidFieldRequest();
1351 }
1352
1353 switch (static_cast<LanParam>(parameter))
1354 {
1355 case LanParam::SetStatus:
1356 {
1357 uint2_t flag;
1358 uint6_t rsvd;
1359 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1360 {
1361 return responseReqDataLenInvalid();
1362 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001363 if (rsvd)
1364 {
1365 return responseInvalidFieldRequest();
1366 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001367 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1368 switch (status)
1369 {
1370 case SetStatus::Complete:
1371 {
1372 getSetStatus(channel) = status;
1373 return responseSuccess();
1374 }
1375 case SetStatus::InProgress:
1376 {
1377 auto& storedStatus = getSetStatus(channel);
1378 if (storedStatus == SetStatus::InProgress)
1379 {
1380 return response(ccParamSetLocked);
1381 }
1382 storedStatus = status;
1383 return responseSuccess();
1384 }
1385 case SetStatus::Commit:
1386 if (getSetStatus(channel) != SetStatus::InProgress)
1387 {
1388 return responseInvalidFieldRequest();
1389 }
1390 return responseSuccess();
1391 }
1392 return response(ccParamNotSupported);
1393 }
1394 case LanParam::AuthSupport:
1395 {
1396 req.trailingOk = true;
1397 return response(ccParamReadOnly);
1398 }
1399 case LanParam::AuthEnables:
1400 {
1401 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001402 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001403 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001404 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001405 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001406 if (channelCall<getDHCPProperty>(channel))
1407 {
1408 return responseCommandNotAvailable();
1409 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001410 in_addr ip;
1411 std::array<uint8_t, sizeof(ip)> bytes;
1412 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1413 {
1414 return responseReqDataLenInvalid();
1415 }
1416 copyInto(ip, bytes);
1417 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1418 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301419 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001420 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301421 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001422 uint4_t flag;
1423 uint4_t rsvd;
1424 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1425 {
1426 return responseReqDataLenInvalid();
1427 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001428 if (rsvd)
1429 {
1430 return responseInvalidFieldRequest();
1431 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001432 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1433 {
1434 case IPSrc::DHCP:
1435 {
1436 channelCall<setDHCPProperty>(channel, true);
1437 return responseSuccess();
1438 }
1439 case IPSrc::Unspecified:
1440 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001441 {
1442 channelCall<setDHCPProperty>(channel, false);
1443 return responseSuccess();
1444 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +05301445 case IPSrc::BIOS:
1446 case IPSrc::BMC:
1447 {
1448 return responseInvalidFieldRequest();
1449 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001450 }
1451 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301452 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001453 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301454 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001455 ether_addr mac;
1456 std::array<uint8_t, sizeof(mac)> bytes;
1457 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301458 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001459 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301460 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001461 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301462
1463 if (!isValidMACAddress(mac))
1464 {
1465 return responseInvalidFieldRequest();
1466 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001467 channelCall<setMACProperty>(channel, mac);
1468 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301469 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001470 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301471 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001472 if (channelCall<getDHCPProperty>(channel))
1473 {
1474 return responseCommandNotAvailable();
1475 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001476 in_addr netmask;
1477 std::array<uint8_t, sizeof(netmask)> bytes;
1478 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301479 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001480 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301481 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001482 copyInto(netmask, bytes);
1483 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1484 netmaskToPrefix(netmask));
1485 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301486 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001487 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301488 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001489 if (channelCall<getDHCPProperty>(channel))
1490 {
1491 return responseCommandNotAvailable();
1492 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001493 in_addr gateway;
1494 std::array<uint8_t, sizeof(gateway)> bytes;
1495 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1496 {
1497 return responseReqDataLenInvalid();
1498 }
1499 copyInto(gateway, bytes);
1500 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1501 return responseSuccess();
1502 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001503 case LanParam::Gateway1MAC:
1504 {
1505 ether_addr gatewayMAC;
1506 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1507 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1508 {
1509 return responseReqDataLenInvalid();
1510 }
1511 copyInto(gatewayMAC, bytes);
1512 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1513 return responseSuccess();
1514 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001515 case LanParam::VLANId:
1516 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301517 uint12_t vlanData = 0;
1518 uint3_t reserved = 0;
1519 bool vlanEnable = 0;
1520
1521 if (req.unpack(vlanData) || req.unpack(reserved) ||
1522 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001523 {
1524 return responseReqDataLenInvalid();
1525 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301526
1527 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001528 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301529 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001530 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301531
1532 uint16_t vlan = static_cast<uint16_t>(vlanData);
1533
1534 if (!vlanEnable)
1535 {
1536 lastDisabledVlan[channel] = vlan;
1537 vlan = 0;
1538 }
1539 channelCall<reconfigureVLAN>(channel, vlan);
1540
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001541 return responseSuccess();
1542 }
1543 case LanParam::CiphersuiteSupport:
1544 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001545 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001546 {
1547 req.trailingOk = true;
1548 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301549 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001550 case LanParam::IPFamilyEnables:
1551 {
1552 uint8_t enables;
1553 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1554 {
1555 return responseReqDataLenInvalid();
1556 }
1557 switch (static_cast<IPFamilyEnables>(enables))
1558 {
1559 case IPFamilyEnables::DualStack:
1560 return responseSuccess();
1561 case IPFamilyEnables::IPv4Only:
1562 case IPFamilyEnables::IPv6Only:
1563 return response(ccParamNotSupported);
1564 }
1565 return response(ccParamNotSupported);
1566 }
1567 case LanParam::IPv6Status:
1568 {
1569 req.trailingOk = true;
1570 return response(ccParamReadOnly);
1571 }
1572 case LanParam::IPv6StaticAddresses:
1573 {
1574 uint8_t set;
1575 uint7_t rsvd;
1576 bool enabled;
1577 in6_addr ip;
1578 std::array<uint8_t, sizeof(ip)> ipbytes;
1579 uint8_t prefix;
1580 uint8_t status;
1581 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1582 !req.fullyUnpacked())
1583 {
1584 return responseReqDataLenInvalid();
1585 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001586 if (rsvd)
1587 {
1588 return responseInvalidFieldRequest();
1589 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001590 copyInto(ip, ipbytes);
1591 if (enabled)
1592 {
1593 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1594 }
1595 else
1596 {
1597 channelCall<deconfigureIfAddr6>(channel, set);
1598 }
1599 return responseSuccess();
1600 }
1601 case LanParam::IPv6DynamicAddresses:
1602 {
1603 req.trailingOk = true;
1604 return response(ccParamReadOnly);
1605 }
1606 case LanParam::IPv6RouterControl:
1607 {
1608 std::bitset<8> control;
1609 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1610 {
1611 return responseReqDataLenInvalid();
1612 }
1613 std::bitset<8> expected;
1614 if (channelCall<getDHCPProperty>(channel))
1615 {
1616 expected[IPv6RouterControlFlag::Dynamic] = 1;
1617 }
1618 else
1619 {
1620 expected[IPv6RouterControlFlag::Static] = 1;
1621 }
1622 if (expected != control)
1623 {
1624 return responseInvalidFieldRequest();
1625 }
1626 return responseSuccess();
1627 }
1628 case LanParam::IPv6StaticRouter1IP:
1629 {
1630 in6_addr gateway;
1631 std::array<uint8_t, sizeof(gateway)> bytes;
1632 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1633 {
1634 return responseReqDataLenInvalid();
1635 }
1636 copyInto(gateway, bytes);
1637 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1638 return responseSuccess();
1639 }
1640 case LanParam::IPv6StaticRouter1MAC:
1641 {
1642 ether_addr mac;
1643 std::array<uint8_t, sizeof(mac)> bytes;
1644 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1645 {
1646 return responseReqDataLenInvalid();
1647 }
1648 copyInto(mac, bytes);
1649 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1650 return responseSuccess();
1651 }
1652 case LanParam::IPv6StaticRouter1PrefixLength:
1653 {
1654 uint8_t prefix;
1655 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1656 {
1657 return responseReqDataLenInvalid();
1658 }
1659 if (prefix != 0)
1660 {
1661 return responseInvalidFieldRequest();
1662 }
1663 return responseSuccess();
1664 }
1665 case LanParam::IPv6StaticRouter1PrefixValue:
1666 {
1667 std::array<uint8_t, sizeof(in6_addr)> bytes;
1668 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1669 {
1670 return responseReqDataLenInvalid();
1671 }
1672 // Accept any prefix value since our prefix length has to be 0
1673 return responseSuccess();
1674 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301675 }
vishwa1eaea4f2016-02-26 11:57:40 -06001676
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001677 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1678 {
1679 return setLanOem(channel, parameter, req);
1680 }
1681
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001682 req.trailingOk = true;
1683 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001684}
1685
vijayabharathix shettycc769252020-02-27 17:52:20 +00001686RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1687 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001688 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301689{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001690 message::Payload ret;
1691 constexpr uint8_t current_revision = 0x11;
1692 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001693
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001694 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301695 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001696 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301697 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001698
vijayabharathix shettycc769252020-02-27 17:52:20 +00001699 const uint8_t channel = convertCurrentChannelNum(
1700 static_cast<uint8_t>(channelBits), ctx->channel);
1701 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001702 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001703 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001704 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001705 }
1706
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001707 static std::vector<uint8_t> cipherList;
1708 static bool listInit = false;
1709 if (!listInit)
1710 {
1711 try
1712 {
1713 cipherList = cipher::getCipherList();
1714 listInit = true;
1715 }
1716 catch (const std::exception& e)
1717 {
1718 }
1719 }
1720
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001721 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301722 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001723 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301724 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001725 SetStatus status;
1726 try
1727 {
1728 status = setStatus.at(channel);
1729 }
1730 catch (const std::out_of_range&)
1731 {
1732 status = SetStatus::Complete;
1733 }
1734 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1735 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301736 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001737 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301738 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001739 std::bitset<6> support;
1740 ret.pack(support, uint2_t{});
1741 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301742 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001743 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001744 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001745 std::bitset<6> enables;
1746 ret.pack(enables, uint2_t{}); // Callback
1747 ret.pack(enables, uint2_t{}); // User
1748 ret.pack(enables, uint2_t{}); // Operator
1749 ret.pack(enables, uint2_t{}); // Admin
1750 ret.pack(enables, uint2_t{}); // OEM
1751 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001752 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001753 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001754 {
1755 auto ifaddr = channelCall<getIfAddr4>(channel);
1756 in_addr addr{};
1757 if (ifaddr)
1758 {
1759 addr = ifaddr->address;
1760 }
1761 ret.pack(dataRef(addr));
1762 return responseSuccess(std::move(ret));
1763 }
1764 case LanParam::IPSrc:
1765 {
1766 auto src = IPSrc::Static;
1767 if (channelCall<getDHCPProperty>(channel))
1768 {
1769 src = IPSrc::DHCP;
1770 }
1771 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1772 return responseSuccess(std::move(ret));
1773 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001774 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001775 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001776 ether_addr mac = channelCall<getMACProperty>(channel);
1777 ret.pack(dataRef(mac));
1778 return responseSuccess(std::move(ret));
1779 }
1780 case LanParam::SubnetMask:
1781 {
1782 auto ifaddr = channelCall<getIfAddr4>(channel);
1783 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1784 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301785 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001786 prefix = ifaddr->prefix;
1787 }
1788 in_addr netmask = prefixToNetmask(prefix);
1789 ret.pack(dataRef(netmask));
1790 return responseSuccess(std::move(ret));
1791 }
1792 case LanParam::Gateway1:
1793 {
1794 auto gateway =
1795 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1796 in_addr{});
1797 ret.pack(dataRef(gateway));
1798 return responseSuccess(std::move(ret));
1799 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001800 case LanParam::Gateway1MAC:
1801 {
1802 ether_addr mac{};
1803 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1804 if (neighbor)
1805 {
1806 mac = neighbor->mac;
1807 }
1808 ret.pack(dataRef(mac));
1809 return responseSuccess(std::move(ret));
1810 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001811 case LanParam::VLANId:
1812 {
1813 uint16_t vlan = channelCall<getVLANProperty>(channel);
1814 if (vlan != 0)
1815 {
1816 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301817 }
1818 else
1819 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001820 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301821 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001822 ret.pack(vlan);
1823 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001824 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001825 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001826 {
1827 if (!listInit)
1828 {
1829 return responseUnspecifiedError();
1830 }
1831 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1832 return responseSuccess(std::move(ret));
1833 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001834 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001835 {
1836 if (!listInit)
1837 {
1838 return responseUnspecifiedError();
1839 }
1840 ret.pack(cipherList);
1841 return responseSuccess(std::move(ret));
1842 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001843 case LanParam::IPFamilySupport:
1844 {
1845 std::bitset<8> support;
1846 support[IPFamilySupportFlag::IPv6Only] = 0;
1847 support[IPFamilySupportFlag::DualStack] = 1;
1848 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1849 ret.pack(support);
1850 return responseSuccess(std::move(ret));
1851 }
1852 case LanParam::IPFamilyEnables:
1853 {
1854 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1855 return responseSuccess(std::move(ret));
1856 }
1857 case LanParam::IPv6Status:
1858 {
1859 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1860 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1861 std::bitset<8> support;
1862 support[IPv6StatusFlag::DHCP] = 1;
1863 support[IPv6StatusFlag::SLAAC] = 1;
1864 ret.pack(support);
1865 return responseSuccess(std::move(ret));
1866 }
1867 case LanParam::IPv6StaticAddresses:
1868 {
1869 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1870 {
1871 return responseParmOutOfRange();
1872 }
1873 getLanIPv6Address(ret, channel, set, originsV6Static);
1874 return responseSuccess(std::move(ret));
1875 }
1876 case LanParam::IPv6DynamicAddresses:
1877 {
1878 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1879 {
1880 return responseParmOutOfRange();
1881 }
1882 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1883 return responseSuccess(std::move(ret));
1884 }
1885 case LanParam::IPv6RouterControl:
1886 {
1887 std::bitset<8> control;
1888 if (channelCall<getDHCPProperty>(channel))
1889 {
1890 control[IPv6RouterControlFlag::Dynamic] = 1;
1891 }
1892 else
1893 {
1894 control[IPv6RouterControlFlag::Static] = 1;
1895 }
1896 ret.pack(control);
1897 return responseSuccess(std::move(ret));
1898 }
1899 case LanParam::IPv6StaticRouter1IP:
1900 {
1901 in6_addr gateway{};
1902 if (!channelCall<getDHCPProperty>(channel))
1903 {
1904 gateway =
1905 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1906 in6_addr{});
1907 }
1908 ret.pack(dataRef(gateway));
1909 return responseSuccess(std::move(ret));
1910 }
1911 case LanParam::IPv6StaticRouter1MAC:
1912 {
1913 ether_addr mac{};
1914 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1915 if (neighbor)
1916 {
1917 mac = neighbor->mac;
1918 }
1919 ret.pack(dataRef(mac));
1920 return responseSuccess(std::move(ret));
1921 }
1922 case LanParam::IPv6StaticRouter1PrefixLength:
1923 {
1924 ret.pack(UINT8_C(0));
1925 return responseSuccess(std::move(ret));
1926 }
1927 case LanParam::IPv6StaticRouter1PrefixValue:
1928 {
1929 in6_addr prefix{};
1930 ret.pack(dataRef(prefix));
1931 return responseSuccess(std::move(ret));
1932 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001933 }
1934
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001935 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1936 {
1937 return getLanOem(channel, parameter, set, block);
1938 }
1939
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001940 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001941}
1942
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001943} // namespace transport
1944} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301945
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001946void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301947
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001948void register_netfn_transport_functions()
1949{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001950 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1951 ipmi::transport::cmdSetLanConfigParameters,
1952 ipmi::Privilege::Admin, ipmi::transport::setLan);
1953 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1954 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001955 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001956}