blob: 6e115350e0e06855ac366cbea0ab2f99cbcdd261 [file] [log] [blame]
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001#include "app/channel.hpp"
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00002#include "user_channel/cipher_mgmt.hpp"
Johnathan Manteyaffadb52019-10-07 10:13:53 -07003
Patrick Venture0b02be92018-08-31 11:55:55 -07004#include <arpa/inet.h>
William A. Kennington IIIc514d872019-04-06 18:19:38 -07005#include <netinet/ether.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07006
William A. Kennington IIIc514d872019-04-06 18:19:38 -07007#include <array>
8#include <bitset>
9#include <cinttypes>
10#include <cstdint>
11#include <cstring>
Johnathan Manteyaffadb52019-10-07 10:13:53 -070012#include <fstream>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070013#include <functional>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070014#include <ipmid/api.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070015#include <ipmid/message.hpp>
16#include <ipmid/message/types.hpp>
17#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070018#include <ipmid/utils.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070019#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070020#include <phosphor-logging/elog-errors.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070021#include <phosphor-logging/elog.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070022#include <phosphor-logging/log.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070023#include <sdbusplus/bus.hpp>
24#include <sdbusplus/exception.hpp>
tomjose26e17732016-03-03 08:52:51 -060025#include <string>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070026#include <string_view>
27#include <type_traits>
28#include <unordered_map>
29#include <unordered_set>
30#include <user_channel/channel_layer.hpp>
31#include <utility>
32#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070033#include <xyz/openbmc_project/Common/error.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070034#include <xyz/openbmc_project/Network/IP/server.hpp>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070035#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070036
William A. Kennington IIIc514d872019-04-06 18:19:38 -070037using phosphor::logging::commit;
38using phosphor::logging::elog;
39using phosphor::logging::entry;
40using phosphor::logging::level;
41using phosphor::logging::log;
42using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
43using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070044using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070045
Johnathan Manteyaffadb52019-10-07 10:13:53 -070046namespace cipher
47{
48
49std::vector<uint8_t> getCipherList()
50{
51 std::vector<uint8_t> cipherList;
52
53 std::ifstream jsonFile(cipher::configFile);
54 if (!jsonFile.is_open())
55 {
56 log<level::ERR>("Channel Cipher suites file not found");
57 elog<InternalFailure>();
58 }
59
60 auto data = Json::parse(jsonFile, nullptr, false);
61 if (data.is_discarded())
62 {
63 log<level::ERR>("Parsing channel cipher suites JSON failed");
64 elog<InternalFailure>();
65 }
66
67 // Byte 1 is reserved
68 cipherList.push_back(0x00);
69
70 for (const auto& record : data)
71 {
72 cipherList.push_back(record.value(cipher, 0));
73 }
74
75 return cipherList;
76}
77} // namespace cipher
78
79namespace ipmi
80{
81namespace transport
82{
83
William A. Kennington IIIc514d872019-04-06 18:19:38 -070084// LAN Handler specific response codes
85constexpr Cc ccParamNotSupported = 0x80;
86constexpr Cc ccParamSetLocked = 0x81;
87constexpr Cc ccParamReadOnly = 0x82;
88
89// VLANs are a 12-bit value
90constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
91constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
92
William A. Kennington III16064aa2019-04-13 17:44:53 -070093// Arbitrary v6 Address Limits to prevent too much output in ipmitool
94constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
95constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
96
William A. Kennington IIIc514d872019-04-06 18:19:38 -070097// D-Bus Network Daemon definitions
98constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
99constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
100
101constexpr auto INTF_SYSTEMCONFIG =
102 "xyz.openbmc_project.Network.SystemConfiguration";
103constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
104constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
105constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
106constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700107constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
108constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
109 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700110constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
111constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
112
113/** @brief Generic paramters for different address families */
114template <int family>
115struct AddrFamily
116{
117};
118
119/** @brief Parameter specialization for IPv4 */
120template <>
121struct AddrFamily<AF_INET>
122{
123 using addr = in_addr;
124 static constexpr auto protocol = IP::Protocol::IPv4;
125 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
126 static constexpr uint8_t defaultPrefix = 32;
127 static constexpr char propertyGateway[] = "DefaultGateway";
128};
129
William A. Kennington III16064aa2019-04-13 17:44:53 -0700130/** @brief Parameter specialization for IPv6 */
131template <>
132struct AddrFamily<AF_INET6>
133{
134 using addr = in6_addr;
135 static constexpr auto protocol = IP::Protocol::IPv6;
136 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
137 static constexpr uint8_t defaultPrefix = 128;
138 static constexpr char propertyGateway[] = "DefaultGateway6";
139};
140
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700141/** @brief Valid address origins for IPv4 */
142const std::unordered_set<IP::AddressOrigin> originsV4 = {
143 IP::AddressOrigin::Static,
144 IP::AddressOrigin::DHCP,
145};
146
William A. Kennington III16064aa2019-04-13 17:44:53 -0700147/** @brief Valid address origins for IPv6 */
148const std::unordered_set<IP::AddressOrigin> originsV6Static = {
149 IP::AddressOrigin::Static};
150const std::unordered_set<IP::AddressOrigin> originsV6Dynamic = {
151 IP::AddressOrigin::DHCP,
152 IP::AddressOrigin::SLAAC,
153};
154
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700155/** @brief Interface IP Address configuration parameters */
156template <int family>
157struct IfAddr
158{
159 std::string path;
160 typename AddrFamily<family>::addr address;
161 IP::AddressOrigin origin;
162 uint8_t prefix;
163};
164
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700165/** @brief Interface Neighbor configuration parameters */
166template <int family>
167struct IfNeigh
168{
169 std::string path;
170 typename AddrFamily<family>::addr ip;
171 ether_addr mac;
172};
173
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700174/** @brief IPMI LAN Parameters */
175enum class LanParam : uint8_t
176{
177 SetStatus = 0,
178 AuthSupport = 1,
179 AuthEnables = 2,
180 IP = 3,
181 IPSrc = 4,
182 MAC = 5,
183 SubnetMask = 6,
184 Gateway1 = 12,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700185 Gateway1MAC = 13,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700186 VLANId = 20,
187 CiphersuiteSupport = 22,
188 CiphersuiteEntries = 23,
jayaprakash Mutyalab741b992019-12-02 17:29:09 +0000189 cipherSuitePrivilegeLevels = 24,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700190 IPFamilySupport = 50,
191 IPFamilyEnables = 51,
192 IPv6Status = 55,
193 IPv6StaticAddresses = 56,
194 IPv6DynamicAddresses = 59,
195 IPv6RouterControl = 64,
196 IPv6StaticRouter1IP = 65,
197 IPv6StaticRouter1MAC = 66,
198 IPv6StaticRouter1PrefixLength = 67,
199 IPv6StaticRouter1PrefixValue = 68,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700200};
201
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700202static constexpr uint8_t oemCmdStart = 192;
203static constexpr uint8_t oemCmdEnd = 255;
204
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700205/** @brief IPMI IP Origin Types */
206enum class IPSrc : uint8_t
207{
208 Unspecified = 0,
209 Static = 1,
210 DHCP = 2,
211 BIOS = 3,
212 BMC = 4,
213};
214
215/** @brief IPMI Set Status */
216enum class SetStatus : uint8_t
217{
218 Complete = 0,
219 InProgress = 1,
220 Commit = 2,
221};
222
William A. Kennington III16064aa2019-04-13 17:44:53 -0700223/** @brief IPMI Family Suport Bits */
224namespace IPFamilySupportFlag
225{
226constexpr uint8_t IPv6Only = 0;
227constexpr uint8_t DualStack = 1;
228constexpr uint8_t IPv6Alerts = 2;
229} // namespace IPFamilySupportFlag
230
231/** @brief IPMI IPFamily Enables Flag */
232enum class IPFamilyEnables : uint8_t
233{
234 IPv4Only = 0,
235 IPv6Only = 1,
236 DualStack = 2,
237};
238
239/** @brief IPMI IPv6 Dyanmic Status Bits */
240namespace IPv6StatusFlag
241{
242constexpr uint8_t DHCP = 0;
243constexpr uint8_t SLAAC = 1;
244}; // namespace IPv6StatusFlag
245
246/** @brief IPMI IPv6 Source */
247enum class IPv6Source : uint8_t
248{
249 Static = 0,
250 SLAAC = 1,
251 DHCP = 2,
252};
253
254/** @brief IPMI IPv6 Address Status */
255enum class IPv6AddressStatus : uint8_t
256{
257 Active = 0,
258 Disabled = 1,
259};
260
261namespace IPv6RouterControlFlag
262{
263constexpr uint8_t Static = 0;
264constexpr uint8_t Dynamic = 1;
265}; // namespace IPv6RouterControlFlag
266
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700267/** @brief A trivial helper used to determine if two PODs are equal
268 *
269 * @params[in] a - The first object to compare
270 * @params[in] b - The second object to compare
271 * @return True if the objects are the same bytewise
272 */
273template <typename T>
274bool equal(const T& a, const T& b)
275{
276 static_assert(std::is_trivially_copyable_v<T>);
277 return std::memcmp(&a, &b, sizeof(T)) == 0;
278}
279
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700280/** @brief Copies bytes from an array into a trivially copyable container
281 *
282 * @params[out] t - The container receiving the data
283 * @params[in] bytes - The data to copy
284 */
285template <size_t N, typename T>
286void copyInto(T& t, const std::array<uint8_t, N>& bytes)
287{
288 static_assert(std::is_trivially_copyable_v<T>);
289 static_assert(N == sizeof(T));
290 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800291}
292
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700293/** @brief Gets a generic view of the bytes in the input container
294 *
295 * @params[in] t - The data to reference
296 * @return A string_view referencing the bytes in the container
297 */
298template <typename T>
299std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600300{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700301 static_assert(std::is_trivially_copyable_v<T>);
302 return {reinterpret_cast<const char*>(&t), sizeof(T)};
303}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530304
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700305/** @brief The dbus parameters for the interface corresponding to a channel
306 * This helps reduce the number of mapper lookups we need for each
307 * query and simplifies finding the VLAN interface if needed.
308 */
309struct ChannelParams
310{
311 /** @brief The channel ID */
312 int id;
313 /** @brief channel name for the interface */
314 std::string ifname;
315 /** @brief Name of the service on the bus */
316 std::string service;
317 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
318 std::string ifPath;
319 /** @brief Logical adapter path used for address assignment */
320 std::string logicalPath;
321};
322
323/** @brief Determines the ethernet interface name corresponding to a channel
324 * Tries to map a VLAN object first so that the address information
325 * is accurate. Otherwise it gets the standard ethernet interface.
326 *
327 * @param[in] bus - The bus object used for lookups
328 * @param[in] channel - The channel id corresponding to an ethernet interface
329 * @return Ethernet interface service and object path if it exists
330 */
331std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
332 uint8_t channel)
333{
334 auto ifname = getChannelName(channel);
335 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800336 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700337 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800338 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800339
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700340 // Enumerate all VLAN + ETHERNET interfaces
341 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
342 "GetSubTree");
343 req.append(PATH_ROOT, 0,
344 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
345 auto reply = bus.call(req);
346 ObjectTree objs;
347 reply.read(objs);
348
349 ChannelParams params;
350 for (const auto& [path, impls] : objs)
351 {
352 if (path.find(ifname) == path.npos)
353 {
354 continue;
355 }
356 for (const auto& [service, intfs] : impls)
357 {
358 bool vlan = false;
359 bool ethernet = false;
360 for (const auto& intf : intfs)
361 {
362 if (intf == INTF_VLAN)
363 {
364 vlan = true;
365 }
366 else if (intf == INTF_ETHERNET)
367 {
368 ethernet = true;
369 }
370 }
371 if (params.service.empty() && (vlan || ethernet))
372 {
373 params.service = service;
374 }
375 if (params.ifPath.empty() && !vlan && ethernet)
376 {
377 params.ifPath = path;
378 }
379 if (params.logicalPath.empty() && vlan)
380 {
381 params.logicalPath = path;
382 }
383 }
384 }
385
386 // We must have a path for the underlying interface
387 if (params.ifPath.empty())
388 {
389 return std::nullopt;
390 }
391 // We don't have a VLAN so the logical path is the same
392 if (params.logicalPath.empty())
393 {
394 params.logicalPath = params.ifPath;
395 }
396
397 params.id = channel;
398 params.ifname = std::move(ifname);
399 return std::move(params);
400}
401
402/** @brief A trivial helper around maybeGetChannelParams() that throws an
403 * exception when it is unable to acquire parameters for the channel.
404 *
405 * @param[in] bus - The bus object used for lookups
406 * @param[in] channel - The channel id corresponding to an ethernet interface
407 * @return Ethernet interface service and object path
408 */
409ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
410{
411 auto params = maybeGetChannelParams(bus, channel);
412 if (!params)
413 {
414 log<level::ERR>("Failed to get channel params",
415 entry("CHANNEL=%" PRIu8, channel));
416 elog<InternalFailure>();
417 }
418 return std::move(*params);
419}
420
421/** @brief Wraps the phosphor logging method to insert some additional metadata
422 *
423 * @param[in] params - The parameters for the channel
424 * ...
425 */
426template <auto level, typename... Args>
427auto logWithChannel(const ChannelParams& params, Args&&... args)
428{
429 return log<level>(std::forward<Args>(args)...,
430 entry("CHANNEL=%d", params.id),
431 entry("IFNAME=%s", params.ifname.c_str()));
432}
433template <auto level, typename... Args>
434auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
435{
436 if (params)
437 {
438 return logWithChannel<level>(*params, std::forward<Args>(args)...);
439 }
440 return log<level>(std::forward<Args>(args)...);
441}
442
443/** @brief Trivializes using parameter getter functions by providing a bus
444 * and channel parameters automatically.
445 *
446 * @param[in] channel - The channel id corresponding to an ethernet interface
447 * ...
448 */
449template <auto func, typename... Args>
450auto channelCall(uint8_t channel, Args&&... args)
451{
452 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
453 auto params = getChannelParams(bus, channel);
454 return std::invoke(func, bus, params, std::forward<Args>(args)...);
455}
456
457/** @brief Determines if the ethernet interface is using DHCP
458 *
459 * @param[in] bus - The bus object used for lookups
460 * @param[in] params - The parameters for the channel
461 * @return True if DHCP is enabled, false otherwise
462 */
463bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
464{
465 return std::get<bool>(getDbusProperty(
466 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
467}
468
469/** @brief Sets the system value for DHCP on the given interface
470 *
471 * @param[in] bus - The bus object used for lookups
472 * @param[in] params - The parameters for the channel
473 * @param[in] on - Whether or not to enable DHCP
474 */
475void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
476 bool on)
477{
478 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
479 "DHCPEnabled", on);
480}
481
482/** @brief Converts a human readable MAC string into MAC bytes
483 *
484 * @param[in] mac - The MAC string
485 * @return MAC in bytes
486 */
487ether_addr stringToMAC(const char* mac)
488{
489 const ether_addr* ret = ether_aton(mac);
490 if (ret == nullptr)
491 {
492 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
493 elog<InternalFailure>();
494 }
495 return *ret;
496}
497
498/** @brief Determines the MAC of the ethernet interface
499 *
500 * @param[in] bus - The bus object used for lookups
501 * @param[in] params - The parameters for the channel
502 * @return The configured mac address
503 */
504ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
505{
506 auto macStr = std::get<std::string>(getDbusProperty(
507 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
508 return stringToMAC(macStr.c_str());
509}
510
511/** @brief Sets the system value for MAC address on the given interface
512 *
513 * @param[in] bus - The bus object used for lookups
514 * @param[in] params - The parameters for the channel
515 * @param[in] mac - MAC address to apply
516 */
517void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
518 const ether_addr& mac)
519{
520 std::string macStr = ether_ntoa(&mac);
521 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
522 macStr);
523}
524
525/** @brief Turns an IP address string into the network byte order form
526 * NOTE: This version strictly validates family matches
527 *
528 * @param[in] address - The string form of the address
529 * @return A network byte order address or none if conversion failed
530 */
531template <int family>
532std::optional<typename AddrFamily<family>::addr>
533 maybeStringToAddr(const char* address)
534{
535 typename AddrFamily<family>::addr ret;
536 if (inet_pton(family, address, &ret) == 1)
537 {
538 return ret;
539 }
540 return std::nullopt;
541}
542
543/** @brief Turns an IP address string into the network byte order form
544 * NOTE: This version strictly validates family matches
545 *
546 * @param[in] address - The string form of the address
547 * @return A network byte order address
548 */
549template <int family>
550typename AddrFamily<family>::addr stringToAddr(const char* address)
551{
552 auto ret = maybeStringToAddr<family>(address);
553 if (!ret)
554 {
555 log<level::ERR>("Failed to convert IP Address",
556 entry("FAMILY=%d", family),
557 entry("ADDRESS=%s", address));
558 elog<InternalFailure>();
559 }
560 return *ret;
561}
562
563/** @brief Turns an IP address in network byte order into a string
564 *
565 * @param[in] address - The string form of the address
566 * @return A network byte order address
567 */
568template <int family>
569std::string addrToString(const typename AddrFamily<family>::addr& address)
570{
571 std::string ret(AddrFamily<family>::maxStrLen, '\0');
572 inet_ntop(family, &address, ret.data(), ret.size());
573 ret.resize(strlen(ret.c_str()));
574 return ret;
575}
576
577/** @brief Retrieves the current gateway for the address family on the system
578 * NOTE: The gateway is currently system wide and not per channel
579 *
580 * @param[in] bus - The bus object used for lookups
581 * @param[in] params - The parameters for the channel
582 * @return An address representing the gateway address if it exists
583 */
584template <int family>
585std::optional<typename AddrFamily<family>::addr>
586 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
587{
588 auto gatewayStr = std::get<std::string>(getDbusProperty(
589 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
590 AddrFamily<family>::propertyGateway));
591 if (gatewayStr.empty())
592 {
593 return std::nullopt;
594 }
595 return stringToAddr<family>(gatewayStr.c_str());
596}
597
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700598/** @brief A lazy lookup mechanism for iterating over object properties stored
599 * in DBus. This will only perform the object lookup when needed, and
600 * retains a cache of previous lookups to speed up future iterations.
601 */
602class ObjectLookupCache
603{
604 public:
605 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
606
607 /** @brief Creates a new ObjectLookupCache for the interface on the bus
608 * NOTE: The inputs to this object must outlive the object since
609 * they are only referenced by it.
610 *
611 * @param[in] bus - The bus object used for lookups
612 * @param[in] params - The parameters for the channel
613 * @param[in] intf - The interface we are looking up
614 */
615 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
616 const char* intf) :
617 bus(bus),
618 params(params), intf(intf),
619 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
620 {
621 }
622
623 class iterator : public ObjectTree::const_iterator
624 {
625 public:
626 using value_type = PropertiesCache::value_type;
627
628 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
629 ObjectTree::const_iterator(it), container(container),
630 ret(container.cache.end())
631 {
632 }
633 value_type& operator*()
634 {
635 ret = container.get(ObjectTree::const_iterator::operator*().first);
636 return *ret;
637 }
638 value_type* operator->()
639 {
640 return &operator*();
641 }
642
643 private:
644 ObjectLookupCache& container;
645 PropertiesCache::iterator ret;
646 };
647
648 iterator begin() noexcept
649 {
650 return iterator(objs.begin(), *this);
651 }
652
653 iterator end() noexcept
654 {
655 return iterator(objs.end(), *this);
656 }
657
658 private:
659 sdbusplus::bus::bus& bus;
660 const ChannelParams& params;
661 const char* const intf;
662 const ObjectTree objs;
663 PropertiesCache cache;
664
665 /** @brief Gets a cached copy of the object properties if possible
666 * Otherwise performs a query on DBus to look them up
667 *
668 * @param[in] path - The object path to lookup
669 * @return An iterator for the specified object path + properties
670 */
671 PropertiesCache::iterator get(const std::string& path)
672 {
673 auto it = cache.find(path);
674 if (it != cache.end())
675 {
676 return it;
677 }
678 auto properties = getAllDbusProperties(bus, params.service, path, intf);
679 return cache.insert({path, std::move(properties)}).first;
680 }
681};
682
683/** @brief Searches the ip object lookup cache for an address matching
684 * the input parameters. NOTE: The index lacks stability across address
685 * changes since the network daemon has no notion of stable indicies.
686 *
687 * @param[in] bus - The bus object used for lookups
688 * @param[in] params - The parameters for the channel
689 * @param[in] idx - The index of the desired address on the interface
690 * @param[in] origins - The allowed origins for the address objects
691 * @param[in] ips - The object lookup cache holding all of the address info
692 * @return The address and prefix if it was found
693 */
694template <int family>
695std::optional<IfAddr<family>>
696 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
697 uint8_t idx,
698 const std::unordered_set<IP::AddressOrigin>& origins,
699 ObjectLookupCache& ips)
700{
701 for (const auto& [path, properties] : ips)
702 {
703 const auto& addrStr = std::get<std::string>(properties.at("Address"));
704 auto addr = maybeStringToAddr<family>(addrStr.c_str());
705 if (!addr)
706 {
707 continue;
708 }
709
710 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
711 std::get<std::string>(properties.at("Origin")));
712 if (origins.find(origin) == origins.end())
713 {
714 continue;
715 }
716
717 if (idx > 0)
718 {
719 idx--;
720 continue;
721 }
722
723 IfAddr<family> ifaddr;
724 ifaddr.path = path;
725 ifaddr.address = *addr;
726 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
727 ifaddr.origin = origin;
728 return std::move(ifaddr);
729 }
730
731 return std::nullopt;
732}
733
734/** @brief Trivial helper around findIfAddr that simplifies calls
735 * for one off lookups. Don't use this if you intend to do multiple
736 * lookups at a time.
737 *
738 * @param[in] bus - The bus object used for lookups
739 * @param[in] params - The parameters for the channel
740 * @param[in] idx - The index of the desired address on the interface
741 * @param[in] origins - The allowed origins for the address objects
742 * @return The address and prefix if it was found
743 */
744template <int family>
745auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
746 uint8_t idx,
747 const std::unordered_set<IP::AddressOrigin>& origins)
748{
749 ObjectLookupCache ips(bus, params, INTF_IP);
750 return findIfAddr<family>(bus, params, idx, origins, ips);
751}
752
753/** @brief Deletes the dbus object. Ignores empty objects or objects that are
754 * missing from the bus.
755 *
756 * @param[in] bus - The bus object used for lookups
757 * @param[in] service - The name of the service
758 * @param[in] path - The path of the object to delete
759 */
760void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
761 const std::string& path)
762{
763 if (path.empty())
764 {
765 return;
766 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530767 try
tomjose26e17732016-03-03 08:52:51 -0600768 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700769 auto req = bus.new_method_call(service.c_str(), path.c_str(),
770 ipmi::DELETE_INTERFACE, "Delete");
771 bus.call_noreply(req);
772 }
773 catch (const sdbusplus::exception::SdBusError& e)
774 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000775 if (strcmp(e.name(),
776 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
777 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600778 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700779 // We want to rethrow real errors
780 throw;
tomjose26e17732016-03-03 08:52:51 -0600781 }
782 }
tomjose26e17732016-03-03 08:52:51 -0600783}
784
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700785/** @brief Sets the address info configured for the interface
786 * If a previous address path exists then it will be removed
787 * before the new address is added.
788 *
789 * @param[in] bus - The bus object used for lookups
790 * @param[in] params - The parameters for the channel
791 * @param[in] address - The address of the new IP
792 * @param[in] prefix - The prefix of the new IP
793 */
794template <int family>
795void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
796 const typename AddrFamily<family>::addr& address,
797 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530798{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700799 auto newreq =
800 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
801 INTF_IP_CREATE, "IP");
802 std::string protocol =
803 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
804 AddrFamily<family>::protocol);
805 newreq.append(protocol, addrToString<family>(address), prefix, "");
806 bus.call_noreply(newreq);
807}
Tom Josepha30c8d32018-03-22 02:15:03 +0530808
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700809/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
810 *
811 * @param[in] bus - The bus object used for lookups
812 * @param[in] params - The parameters for the channel
813 * @return The address and prefix if found
814 */
815auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530816{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700817 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
818}
Tom Josepha30c8d32018-03-22 02:15:03 +0530819
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700820/** @brief Reconfigures the IPv4 address info configured for the interface
821 *
822 * @param[in] bus - The bus object used for lookups
823 * @param[in] params - The parameters for the channel
824 * @param[in] address - The new address if specified
825 * @param[in] prefix - The new address prefix if specified
826 */
827void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
828 const std::optional<in_addr>& address,
829 std::optional<uint8_t> prefix)
830{
831 auto ifaddr = getIfAddr4(bus, params);
832 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530833 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700834 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530835 elog<InternalFailure>();
836 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700837 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
838 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530839 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700840 fallbackPrefix = ifaddr->prefix;
841 deleteObjectIfExists(bus, params.service, ifaddr->path);
842 }
843 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
844 prefix.value_or(fallbackPrefix));
845}
846
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700847template <int family>
848std::optional<IfNeigh<family>>
849 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
850 const typename AddrFamily<family>::addr& ip,
851 ObjectLookupCache& neighbors)
852{
853 const auto state =
854 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
855 Neighbor::State::Permanent);
856 for (const auto& [path, neighbor] : neighbors)
857 {
858 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
859 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
860 if (!neighIP)
861 {
862 continue;
863 }
864 if (!equal(*neighIP, ip))
865 {
866 continue;
867 }
868 if (state != std::get<std::string>(neighbor.at("State")))
869 {
870 continue;
871 }
872
873 IfNeigh<family> ret;
874 ret.path = path;
875 ret.ip = ip;
876 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
877 ret.mac = stringToMAC(macStr.c_str());
878 return std::move(ret);
879 }
880
881 return std::nullopt;
882}
883
884template <int family>
885void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
886 const typename AddrFamily<family>::addr& address,
887 const ether_addr& mac)
888{
889 auto newreq =
890 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
891 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
892 std::string macStr = ether_ntoa(&mac);
893 newreq.append(addrToString<family>(address), macStr);
894 bus.call_noreply(newreq);
895}
896
897/** @brief Sets the system wide value for the default gateway
898 *
899 * @param[in] bus - The bus object used for lookups
900 * @param[in] params - The parameters for the channel
901 * @param[in] gateway - Gateway address to apply
902 */
903template <int family>
904void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
905 const typename AddrFamily<family>::addr& address)
906{
907 // Save the old gateway MAC address if it exists so we can recreate it
908 auto gateway = getGatewayProperty<family>(bus, params);
909 std::optional<IfNeigh<family>> neighbor;
910 if (gateway)
911 {
912 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
913 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
914 }
915
916 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
917 AddrFamily<family>::propertyGateway,
918 addrToString<family>(address));
919
920 // Restore the gateway MAC if we had one
921 if (neighbor)
922 {
923 deleteObjectIfExists(bus, params.service, neighbor->path);
924 createNeighbor<family>(bus, params, address, neighbor->mac);
925 }
926}
927
928template <int family>
929std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
930 const ChannelParams& params,
931 ObjectLookupCache& neighbors)
932{
933 auto gateway = getGatewayProperty<family>(bus, params);
934 if (!gateway)
935 {
936 return std::nullopt;
937 }
938
939 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
940}
941
942template <int family>
943std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
944 const ChannelParams& params)
945{
946 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
947 return findGatewayNeighbor<family>(bus, params, neighbors);
948}
949
950template <int family>
951void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
952 const ChannelParams& params, const ether_addr& mac)
953{
954 auto gateway = getGatewayProperty<family>(bus, params);
955 if (!gateway)
956 {
957 log<level::ERR>("Tried to set Gateway MAC without Gateway");
958 elog<InternalFailure>();
959 }
960
961 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
962 auto neighbor =
963 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
964 if (neighbor)
965 {
966 deleteObjectIfExists(bus, params.service, neighbor->path);
967 }
968
969 createNeighbor<family>(bus, params, *gateway, mac);
970}
971
William A. Kennington III16064aa2019-04-13 17:44:53 -0700972/** @brief Deconfigures the IPv6 address info configured for the interface
973 *
974 * @param[in] bus - The bus object used for lookups
975 * @param[in] params - The parameters for the channel
976 * @param[in] idx - The address index to operate on
977 */
978void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
979 uint8_t idx)
980{
981 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
982 if (ifaddr)
983 {
984 deleteObjectIfExists(bus, params.service, ifaddr->path);
985 }
986}
987
988/** @brief Reconfigures the IPv6 address info configured for the interface
989 *
990 * @param[in] bus - The bus object used for lookups
991 * @param[in] params - The parameters for the channel
992 * @param[in] idx - The address index to operate on
993 * @param[in] address - The new address
994 * @param[in] prefix - The new address prefix
995 */
996void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
997 uint8_t idx, const in6_addr& address, uint8_t prefix)
998{
999 deconfigureIfAddr6(bus, params, idx);
1000 createIfAddr<AF_INET6>(bus, params, address, prefix);
1001}
1002
1003/** @brief Converts the AddressOrigin into an IPv6Source
1004 *
1005 * @param[in] origin - The DBus Address Origin to convert
1006 * @return The IPv6Source version of the origin
1007 */
1008IPv6Source originToSourceType(IP::AddressOrigin origin)
1009{
1010 switch (origin)
1011 {
1012 case IP::AddressOrigin::Static:
1013 return IPv6Source::Static;
1014 case IP::AddressOrigin::DHCP:
1015 return IPv6Source::DHCP;
1016 case IP::AddressOrigin::SLAAC:
1017 return IPv6Source::SLAAC;
1018 default:
1019 {
1020 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
1021 convertForMessage(origin);
1022 log<level::ERR>(
1023 "Invalid IP::AddressOrigin conversion to IPv6Source",
1024 entry("ORIGIN=%s", originStr.c_str()));
1025 elog<InternalFailure>();
1026 }
1027 }
1028}
1029
1030/** @brief Packs the IPMI message response with IPv6 address data
1031 *
1032 * @param[out] ret - The IPMI response payload to be packed
1033 * @param[in] channel - The channel id corresponding to an ethernet interface
1034 * @param[in] set - The set selector for determining address index
1035 * @param[in] origins - Set of valid origins for address filtering
1036 */
1037void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
1038 const std::unordered_set<IP::AddressOrigin>& origins)
1039{
1040 auto source = IPv6Source::Static;
1041 bool enabled = false;
1042 in6_addr addr{};
1043 uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
1044 auto status = IPv6AddressStatus::Disabled;
1045
1046 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
1047 if (ifaddr)
1048 {
1049 source = originToSourceType(ifaddr->origin);
1050 enabled = true;
1051 addr = ifaddr->address;
1052 prefix = ifaddr->prefix;
1053 status = IPv6AddressStatus::Active;
1054 }
1055
1056 ret.pack(set);
1057 ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled);
1058 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
1059 ret.pack(prefix);
1060 ret.pack(static_cast<uint8_t>(status));
1061}
1062
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001063/** @brief Gets the vlan ID configured on the interface
1064 *
1065 * @param[in] bus - The bus object used for lookups
1066 * @param[in] params - The parameters for the channel
1067 * @return VLAN id or the standard 0 for no VLAN
1068 */
1069uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
1070{
1071 // VLAN devices will always have a separate logical object
1072 if (params.ifPath == params.logicalPath)
1073 {
1074 return 0;
1075 }
1076
1077 auto vlan = std::get<uint32_t>(getDbusProperty(
1078 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
1079 if ((vlan & VLAN_VALUE_MASK) != vlan)
1080 {
1081 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
1082 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +05301083 elog<InternalFailure>();
1084 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001085 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +05301086}
1087
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001088/** @brief Deletes all of the possible configuration parameters for a channel
1089 *
1090 * @param[in] bus - The bus object used for lookups
1091 * @param[in] params - The parameters for the channel
1092 */
1093void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001094{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001095 // Delete all objects associated with the interface
1096 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
1097 "GetSubTree");
1098 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
1099 auto objreply = bus.call(objreq);
1100 ObjectTree objs;
1101 objreply.read(objs);
1102 for (const auto& [path, impls] : objs)
1103 {
1104 if (path.find(params.ifname) == path.npos)
1105 {
1106 continue;
1107 }
1108 for (const auto& [service, intfs] : impls)
1109 {
1110 deleteObjectIfExists(bus, service, path);
1111 }
1112 // Update params to reflect the deletion of vlan
1113 if (path == params.logicalPath)
1114 {
1115 params.logicalPath = params.ifPath;
1116 }
1117 }
1118
1119 // Clear out any settings on the lower physical interface
1120 setDHCPProperty(bus, params, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001121}
1122
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001123/** @brief Creates a new VLAN on the specified interface
1124 *
1125 * @param[in] bus - The bus object used for lookups
1126 * @param[in] params - The parameters for the channel
1127 * @param[in] vlan - The id of the new vlan
1128 */
1129void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +05301130{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001131 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301132 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001133 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301134 }
1135
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001136 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
1137 INTF_VLAN_CREATE, "VLAN");
1138 req.append(params.ifname, static_cast<uint32_t>(vlan));
1139 auto reply = bus.call(req);
1140 sdbusplus::message::object_path newPath;
1141 reply.read(newPath);
1142 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301143}
1144
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001145/** @brief Performs the necessary reconfiguration to change the VLAN
1146 *
1147 * @param[in] bus - The bus object used for lookups
1148 * @param[in] params - The parameters for the channel
1149 * @param[in] vlan - The new vlan id to use
1150 */
1151void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
1152 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001153{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001154 // Unfortunatetly we don't have built-in functions to migrate our interface
1155 // customizations to new VLAN interfaces, or have some kind of decoupling.
1156 // We therefore must retain all of our old information, setup the new VLAN
1157 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +08001158
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001159 // Save info from the old logical interface
1160 ObjectLookupCache ips(bus, params, INTF_IP);
1161 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001162 std::vector<IfAddr<AF_INET6>> ifaddrs6;
1163 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
1164 {
1165 auto ifaddr6 =
1166 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
1167 if (!ifaddr6)
1168 {
1169 break;
1170 }
1171 ifaddrs6.push_back(std::move(*ifaddr6));
1172 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001173 auto dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001174 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1175 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001176 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001177
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001178 deconfigureChannel(bus, params);
1179 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001180
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001181 // Re-establish the saved settings
1182 setDHCPProperty(bus, params, dhcp);
1183 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001184 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001185 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001186 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001187 for (const auto& ifaddr6 : ifaddrs6)
1188 {
1189 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
1190 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001191 if (neighbor4)
1192 {
1193 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
1194 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001195 if (neighbor6)
1196 {
1197 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
1198 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001199}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001200
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001201/** @brief Turns a prefix into a netmask
1202 *
1203 * @param[in] prefix - The prefix length
1204 * @return The netmask
1205 */
1206in_addr prefixToNetmask(uint8_t prefix)
1207{
1208 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001209 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001210 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
1211 elog<InternalFailure>();
1212 }
1213 if (prefix == 0)
1214 {
1215 // Avoids 32-bit lshift by 32 UB
1216 return {};
1217 }
1218 return {htobe32(~UINT32_C(0) << (32 - prefix))};
1219}
1220
1221/** @brief Turns a a netmask into a prefix length
1222 *
1223 * @param[in] netmask - The netmask in byte form
1224 * @return The prefix length
1225 */
1226uint8_t netmaskToPrefix(in_addr netmask)
1227{
1228 uint32_t x = be32toh(netmask.s_addr);
1229 if ((~x & (~x + 1)) != 0)
1230 {
1231 char maskStr[INET_ADDRSTRLEN];
1232 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
1233 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
1234 elog<InternalFailure>();
1235 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -08001236 return static_cast<bool>(x)
1237 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
1238 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001239}
1240
1241// We need to store this value so it can be returned to the client
1242// It is volatile so safe to store in daemon memory.
1243static std::unordered_map<uint8_t, SetStatus> setStatus;
1244
1245// Until we have good support for fixed versions of IPMI tool
1246// we need to return the VLAN id for disabled VLANs. The value is only
1247// used for verification that a disable operation succeeded and will only
1248// be sent if our system indicates that vlans are disabled.
1249static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
1250
1251/** @brief Gets the set status for the channel if it exists
1252 * Otherise populates and returns the default value.
1253 *
1254 * @param[in] channel - The channel id corresponding to an ethernet interface
1255 * @return A reference to the SetStatus for the channel
1256 */
1257SetStatus& getSetStatus(uint8_t channel)
1258{
1259 auto it = setStatus.find(channel);
1260 if (it != setStatus.end())
1261 {
1262 return it->second;
1263 }
1264 return setStatus[channel] = SetStatus::Complete;
1265}
1266
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001267/**
1268 * Define placeholder command handlers for the OEM Extension bytes for the Set
1269 * LAN Configuration Parameters and Get LAN Configuration Parameters
1270 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
1271 * functions below to be overridden.
1272 * To create handlers for your own proprietary command set:
1273 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
1274 * recipe
1275 * Create C++ file(s) that define IPMI handler functions matching the
1276 * function names below (i.e. setLanOem). The default name for the
1277 * transport IPMI commands is transporthandler_oem.cpp.
1278 * Add:
1279 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
1280 * Create a do_compile_prepend()/do_install_append method in your
1281 * bbappend file to copy the file to the build directory.
1282 * Add:
1283 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
1284 * # Copy the "strong" functions into the working directory, overriding the
1285 * # placeholder functions.
1286 * do_compile_prepend(){
1287 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
1288 * }
1289 *
1290 * # Clean up after complilation has completed
1291 * do_install_append(){
1292 * rm -f ${S}/transporthandler_oem.cpp
1293 * }
1294 *
1295 */
1296
1297/**
1298 * Define the placeholder OEM commands as having weak linkage. Create
1299 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
1300 * file. The functions defined there must not have the "weak" attribute
1301 * applied to them.
1302 */
1303RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1304 __attribute__((weak));
1305RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1306 uint8_t set, uint8_t block)
1307 __attribute__((weak));
1308
1309RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1310{
1311 req.trailingOk = true;
1312 return response(ccParamNotSupported);
1313}
1314
1315RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1316 uint8_t set, uint8_t block)
1317{
1318 return response(ccParamNotSupported);
1319}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301320/**
1321 * @brief is MAC address valid.
1322 *
1323 * This function checks whether the MAC address is valid or not.
1324 *
1325 * @param[in] mac - MAC address.
1326 * @return true if MAC address is valid else retun false.
1327 **/
1328bool isValidMACAddress(const ether_addr& mac)
1329{
1330 // check if mac address is empty
1331 if (equal(mac, ether_addr{}))
1332 {
1333 return false;
1334 }
1335 // we accept only unicast MAC addresses and same thing has been checked in
1336 // phosphor-network layer. If the least significant bit of the first octet
1337 // is set to 1, it is multicast MAC else it is unicast MAC address.
1338 if (mac.ether_addr_octet[0] & 1)
1339 {
1340 return false;
1341 }
1342 return true;
1343}
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001344
vijayabharathix shettycc769252020-02-27 17:52:20 +00001345RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1346 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001347{
vijayabharathix shettycc769252020-02-27 17:52:20 +00001348 const uint8_t channel = convertCurrentChannelNum(
1349 static_cast<uint8_t>(channelBits), ctx->channel);
1350 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001351 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001352 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001353 req.trailingOk = true;
1354 return responseInvalidFieldRequest();
1355 }
1356
1357 switch (static_cast<LanParam>(parameter))
1358 {
1359 case LanParam::SetStatus:
1360 {
1361 uint2_t flag;
1362 uint6_t rsvd;
1363 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1364 {
1365 return responseReqDataLenInvalid();
1366 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001367 if (rsvd)
1368 {
1369 return responseInvalidFieldRequest();
1370 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001371 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1372 switch (status)
1373 {
1374 case SetStatus::Complete:
1375 {
1376 getSetStatus(channel) = status;
1377 return responseSuccess();
1378 }
1379 case SetStatus::InProgress:
1380 {
1381 auto& storedStatus = getSetStatus(channel);
1382 if (storedStatus == SetStatus::InProgress)
1383 {
1384 return response(ccParamSetLocked);
1385 }
1386 storedStatus = status;
1387 return responseSuccess();
1388 }
1389 case SetStatus::Commit:
1390 if (getSetStatus(channel) != SetStatus::InProgress)
1391 {
1392 return responseInvalidFieldRequest();
1393 }
1394 return responseSuccess();
1395 }
1396 return response(ccParamNotSupported);
1397 }
1398 case LanParam::AuthSupport:
1399 {
1400 req.trailingOk = true;
1401 return response(ccParamReadOnly);
1402 }
1403 case LanParam::AuthEnables:
1404 {
1405 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001406 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001407 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001408 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001409 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001410 if (channelCall<getDHCPProperty>(channel))
1411 {
1412 return responseCommandNotAvailable();
1413 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001414 in_addr ip;
1415 std::array<uint8_t, sizeof(ip)> bytes;
1416 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1417 {
1418 return responseReqDataLenInvalid();
1419 }
1420 copyInto(ip, bytes);
1421 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1422 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301423 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001424 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301425 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001426 uint4_t flag;
1427 uint4_t rsvd;
1428 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1429 {
1430 return responseReqDataLenInvalid();
1431 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001432 if (rsvd)
1433 {
1434 return responseInvalidFieldRequest();
1435 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001436 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1437 {
1438 case IPSrc::DHCP:
1439 {
1440 channelCall<setDHCPProperty>(channel, true);
1441 return responseSuccess();
1442 }
1443 case IPSrc::Unspecified:
1444 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001445 {
1446 channelCall<setDHCPProperty>(channel, false);
1447 return responseSuccess();
1448 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +05301449 case IPSrc::BIOS:
1450 case IPSrc::BMC:
1451 {
1452 return responseInvalidFieldRequest();
1453 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001454 }
1455 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301456 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001457 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301458 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001459 ether_addr mac;
1460 std::array<uint8_t, sizeof(mac)> bytes;
1461 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301462 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001463 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301464 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001465 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301466
1467 if (!isValidMACAddress(mac))
1468 {
1469 return responseInvalidFieldRequest();
1470 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001471 channelCall<setMACProperty>(channel, mac);
1472 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301473 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001474 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301475 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001476 if (channelCall<getDHCPProperty>(channel))
1477 {
1478 return responseCommandNotAvailable();
1479 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001480 in_addr netmask;
1481 std::array<uint8_t, sizeof(netmask)> bytes;
1482 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301483 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001484 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301485 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001486 copyInto(netmask, bytes);
1487 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1488 netmaskToPrefix(netmask));
1489 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301490 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001491 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301492 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001493 if (channelCall<getDHCPProperty>(channel))
1494 {
1495 return responseCommandNotAvailable();
1496 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001497 in_addr gateway;
1498 std::array<uint8_t, sizeof(gateway)> bytes;
1499 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1500 {
1501 return responseReqDataLenInvalid();
1502 }
1503 copyInto(gateway, bytes);
1504 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1505 return responseSuccess();
1506 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001507 case LanParam::Gateway1MAC:
1508 {
1509 ether_addr gatewayMAC;
1510 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1511 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1512 {
1513 return responseReqDataLenInvalid();
1514 }
1515 copyInto(gatewayMAC, bytes);
1516 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1517 return responseSuccess();
1518 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001519 case LanParam::VLANId:
1520 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301521 uint12_t vlanData = 0;
1522 uint3_t reserved = 0;
1523 bool vlanEnable = 0;
1524
1525 if (req.unpack(vlanData) || req.unpack(reserved) ||
1526 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001527 {
1528 return responseReqDataLenInvalid();
1529 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301530
1531 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001532 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301533 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001534 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301535
1536 uint16_t vlan = static_cast<uint16_t>(vlanData);
1537
1538 if (!vlanEnable)
1539 {
1540 lastDisabledVlan[channel] = vlan;
1541 vlan = 0;
1542 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001543 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1544 {
1545 return responseInvalidFieldRequest();
1546 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301547
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001548 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001549 return responseSuccess();
1550 }
1551 case LanParam::CiphersuiteSupport:
1552 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001553 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001554 {
1555 req.trailingOk = true;
1556 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301557 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001558 case LanParam::IPFamilyEnables:
1559 {
1560 uint8_t enables;
1561 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1562 {
1563 return responseReqDataLenInvalid();
1564 }
1565 switch (static_cast<IPFamilyEnables>(enables))
1566 {
1567 case IPFamilyEnables::DualStack:
1568 return responseSuccess();
1569 case IPFamilyEnables::IPv4Only:
1570 case IPFamilyEnables::IPv6Only:
1571 return response(ccParamNotSupported);
1572 }
1573 return response(ccParamNotSupported);
1574 }
1575 case LanParam::IPv6Status:
1576 {
1577 req.trailingOk = true;
1578 return response(ccParamReadOnly);
1579 }
1580 case LanParam::IPv6StaticAddresses:
1581 {
1582 uint8_t set;
1583 uint7_t rsvd;
1584 bool enabled;
1585 in6_addr ip;
1586 std::array<uint8_t, sizeof(ip)> ipbytes;
1587 uint8_t prefix;
1588 uint8_t status;
1589 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1590 !req.fullyUnpacked())
1591 {
1592 return responseReqDataLenInvalid();
1593 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001594 if (rsvd)
1595 {
1596 return responseInvalidFieldRequest();
1597 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001598 copyInto(ip, ipbytes);
1599 if (enabled)
1600 {
1601 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1602 }
1603 else
1604 {
1605 channelCall<deconfigureIfAddr6>(channel, set);
1606 }
1607 return responseSuccess();
1608 }
1609 case LanParam::IPv6DynamicAddresses:
1610 {
1611 req.trailingOk = true;
1612 return response(ccParamReadOnly);
1613 }
1614 case LanParam::IPv6RouterControl:
1615 {
1616 std::bitset<8> control;
1617 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1618 {
1619 return responseReqDataLenInvalid();
1620 }
1621 std::bitset<8> expected;
1622 if (channelCall<getDHCPProperty>(channel))
1623 {
1624 expected[IPv6RouterControlFlag::Dynamic] = 1;
1625 }
1626 else
1627 {
1628 expected[IPv6RouterControlFlag::Static] = 1;
1629 }
1630 if (expected != control)
1631 {
1632 return responseInvalidFieldRequest();
1633 }
1634 return responseSuccess();
1635 }
1636 case LanParam::IPv6StaticRouter1IP:
1637 {
1638 in6_addr gateway;
1639 std::array<uint8_t, sizeof(gateway)> bytes;
1640 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1641 {
1642 return responseReqDataLenInvalid();
1643 }
1644 copyInto(gateway, bytes);
1645 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1646 return responseSuccess();
1647 }
1648 case LanParam::IPv6StaticRouter1MAC:
1649 {
1650 ether_addr mac;
1651 std::array<uint8_t, sizeof(mac)> bytes;
1652 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1653 {
1654 return responseReqDataLenInvalid();
1655 }
1656 copyInto(mac, bytes);
1657 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1658 return responseSuccess();
1659 }
1660 case LanParam::IPv6StaticRouter1PrefixLength:
1661 {
1662 uint8_t prefix;
1663 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1664 {
1665 return responseReqDataLenInvalid();
1666 }
1667 if (prefix != 0)
1668 {
1669 return responseInvalidFieldRequest();
1670 }
1671 return responseSuccess();
1672 }
1673 case LanParam::IPv6StaticRouter1PrefixValue:
1674 {
1675 std::array<uint8_t, sizeof(in6_addr)> bytes;
1676 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1677 {
1678 return responseReqDataLenInvalid();
1679 }
1680 // Accept any prefix value since our prefix length has to be 0
1681 return responseSuccess();
1682 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001683 case LanParam::cipherSuitePrivilegeLevels:
1684 {
1685 uint8_t reserved;
1686 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1687
1688 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1689 {
1690 return responseReqDataLenInvalid();
1691 }
1692
1693 if (reserved)
1694 {
1695 return responseInvalidFieldRequest();
1696 }
1697
1698 uint8_t resp =
1699 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1700 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1701 if (!resp)
1702 {
1703 return responseSuccess();
1704 }
1705 else
1706 {
1707 req.trailingOk = true;
1708 return response(resp);
1709 }
1710 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301711 }
vishwa1eaea4f2016-02-26 11:57:40 -06001712
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001713 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1714 {
1715 return setLanOem(channel, parameter, req);
1716 }
1717
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001718 req.trailingOk = true;
1719 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001720}
1721
vijayabharathix shettycc769252020-02-27 17:52:20 +00001722RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1723 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001724 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301725{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001726 message::Payload ret;
1727 constexpr uint8_t current_revision = 0x11;
1728 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001729
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001730 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301731 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001732 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301733 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001734
vijayabharathix shettycc769252020-02-27 17:52:20 +00001735 const uint8_t channel = convertCurrentChannelNum(
1736 static_cast<uint8_t>(channelBits), ctx->channel);
1737 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001738 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001739 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001740 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001741 }
1742
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001743 static std::vector<uint8_t> cipherList;
1744 static bool listInit = false;
1745 if (!listInit)
1746 {
1747 try
1748 {
1749 cipherList = cipher::getCipherList();
1750 listInit = true;
1751 }
1752 catch (const std::exception& e)
1753 {
1754 }
1755 }
1756
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001757 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301758 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001759 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301760 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001761 SetStatus status;
1762 try
1763 {
1764 status = setStatus.at(channel);
1765 }
1766 catch (const std::out_of_range&)
1767 {
1768 status = SetStatus::Complete;
1769 }
1770 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1771 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301772 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001773 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301774 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001775 std::bitset<6> support;
1776 ret.pack(support, uint2_t{});
1777 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301778 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001779 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001780 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001781 std::bitset<6> enables;
1782 ret.pack(enables, uint2_t{}); // Callback
1783 ret.pack(enables, uint2_t{}); // User
1784 ret.pack(enables, uint2_t{}); // Operator
1785 ret.pack(enables, uint2_t{}); // Admin
1786 ret.pack(enables, uint2_t{}); // OEM
1787 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001788 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001789 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001790 {
1791 auto ifaddr = channelCall<getIfAddr4>(channel);
1792 in_addr addr{};
1793 if (ifaddr)
1794 {
1795 addr = ifaddr->address;
1796 }
1797 ret.pack(dataRef(addr));
1798 return responseSuccess(std::move(ret));
1799 }
1800 case LanParam::IPSrc:
1801 {
1802 auto src = IPSrc::Static;
1803 if (channelCall<getDHCPProperty>(channel))
1804 {
1805 src = IPSrc::DHCP;
1806 }
1807 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1808 return responseSuccess(std::move(ret));
1809 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001810 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001811 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001812 ether_addr mac = channelCall<getMACProperty>(channel);
1813 ret.pack(dataRef(mac));
1814 return responseSuccess(std::move(ret));
1815 }
1816 case LanParam::SubnetMask:
1817 {
1818 auto ifaddr = channelCall<getIfAddr4>(channel);
1819 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1820 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301821 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001822 prefix = ifaddr->prefix;
1823 }
1824 in_addr netmask = prefixToNetmask(prefix);
1825 ret.pack(dataRef(netmask));
1826 return responseSuccess(std::move(ret));
1827 }
1828 case LanParam::Gateway1:
1829 {
1830 auto gateway =
1831 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1832 in_addr{});
1833 ret.pack(dataRef(gateway));
1834 return responseSuccess(std::move(ret));
1835 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001836 case LanParam::Gateway1MAC:
1837 {
1838 ether_addr mac{};
1839 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1840 if (neighbor)
1841 {
1842 mac = neighbor->mac;
1843 }
1844 ret.pack(dataRef(mac));
1845 return responseSuccess(std::move(ret));
1846 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001847 case LanParam::VLANId:
1848 {
1849 uint16_t vlan = channelCall<getVLANProperty>(channel);
1850 if (vlan != 0)
1851 {
1852 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301853 }
1854 else
1855 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001856 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301857 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001858 ret.pack(vlan);
1859 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001860 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001861 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001862 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001863 if (getChannelSessionSupport(channel) ==
1864 EChannelSessSupported::none)
1865 {
1866 return responseInvalidFieldRequest();
1867 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001868 if (!listInit)
1869 {
1870 return responseUnspecifiedError();
1871 }
1872 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1873 return responseSuccess(std::move(ret));
1874 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001875 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001876 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001877 if (getChannelSessionSupport(channel) ==
1878 EChannelSessSupported::none)
1879 {
1880 return responseInvalidFieldRequest();
1881 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001882 if (!listInit)
1883 {
1884 return responseUnspecifiedError();
1885 }
1886 ret.pack(cipherList);
1887 return responseSuccess(std::move(ret));
1888 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001889 case LanParam::IPFamilySupport:
1890 {
1891 std::bitset<8> support;
1892 support[IPFamilySupportFlag::IPv6Only] = 0;
1893 support[IPFamilySupportFlag::DualStack] = 1;
1894 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1895 ret.pack(support);
1896 return responseSuccess(std::move(ret));
1897 }
1898 case LanParam::IPFamilyEnables:
1899 {
1900 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1901 return responseSuccess(std::move(ret));
1902 }
1903 case LanParam::IPv6Status:
1904 {
1905 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1906 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1907 std::bitset<8> support;
1908 support[IPv6StatusFlag::DHCP] = 1;
1909 support[IPv6StatusFlag::SLAAC] = 1;
1910 ret.pack(support);
1911 return responseSuccess(std::move(ret));
1912 }
1913 case LanParam::IPv6StaticAddresses:
1914 {
1915 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1916 {
1917 return responseParmOutOfRange();
1918 }
1919 getLanIPv6Address(ret, channel, set, originsV6Static);
1920 return responseSuccess(std::move(ret));
1921 }
1922 case LanParam::IPv6DynamicAddresses:
1923 {
1924 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1925 {
1926 return responseParmOutOfRange();
1927 }
1928 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1929 return responseSuccess(std::move(ret));
1930 }
1931 case LanParam::IPv6RouterControl:
1932 {
1933 std::bitset<8> control;
1934 if (channelCall<getDHCPProperty>(channel))
1935 {
1936 control[IPv6RouterControlFlag::Dynamic] = 1;
1937 }
1938 else
1939 {
1940 control[IPv6RouterControlFlag::Static] = 1;
1941 }
1942 ret.pack(control);
1943 return responseSuccess(std::move(ret));
1944 }
1945 case LanParam::IPv6StaticRouter1IP:
1946 {
1947 in6_addr gateway{};
1948 if (!channelCall<getDHCPProperty>(channel))
1949 {
1950 gateway =
1951 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1952 in6_addr{});
1953 }
1954 ret.pack(dataRef(gateway));
1955 return responseSuccess(std::move(ret));
1956 }
1957 case LanParam::IPv6StaticRouter1MAC:
1958 {
1959 ether_addr mac{};
1960 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1961 if (neighbor)
1962 {
1963 mac = neighbor->mac;
1964 }
1965 ret.pack(dataRef(mac));
1966 return responseSuccess(std::move(ret));
1967 }
1968 case LanParam::IPv6StaticRouter1PrefixLength:
1969 {
1970 ret.pack(UINT8_C(0));
1971 return responseSuccess(std::move(ret));
1972 }
1973 case LanParam::IPv6StaticRouter1PrefixValue:
1974 {
1975 in6_addr prefix{};
1976 ret.pack(dataRef(prefix));
1977 return responseSuccess(std::move(ret));
1978 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001979 case LanParam::cipherSuitePrivilegeLevels:
1980 {
1981 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1982
1983 uint8_t resp =
1984 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1985 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1986 if (!resp)
1987 {
1988 constexpr uint8_t reserved1 = 0x00;
1989 ret.pack(reserved1, csPrivilegeLevels);
1990 return responseSuccess(std::move(ret));
1991 }
1992 else
1993 {
1994 return response(resp);
1995 }
1996 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001997 }
1998
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001999 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
2000 {
2001 return getLanOem(channel, parameter, set, block);
2002 }
2003
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002004 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002005}
2006
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002007} // namespace transport
2008} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302009
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002010void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302011
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002012void register_netfn_transport_functions()
2013{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002014 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2015 ipmi::transport::cmdSetLanConfigParameters,
2016 ipmi::Privilege::Admin, ipmi::transport::setLan);
2017 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2018 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08002019 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002020}