blob: 3813d055c49d3ac62be39ba910eb52947059879b [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 {
775 if (strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600776 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700777 // We want to rethrow real errors
778 throw;
tomjose26e17732016-03-03 08:52:51 -0600779 }
780 }
tomjose26e17732016-03-03 08:52:51 -0600781}
782
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700783/** @brief Sets the address info configured for the interface
784 * If a previous address path exists then it will be removed
785 * before the new address is added.
786 *
787 * @param[in] bus - The bus object used for lookups
788 * @param[in] params - The parameters for the channel
789 * @param[in] address - The address of the new IP
790 * @param[in] prefix - The prefix of the new IP
791 */
792template <int family>
793void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
794 const typename AddrFamily<family>::addr& address,
795 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530796{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700797 auto newreq =
798 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
799 INTF_IP_CREATE, "IP");
800 std::string protocol =
801 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
802 AddrFamily<family>::protocol);
803 newreq.append(protocol, addrToString<family>(address), prefix, "");
804 bus.call_noreply(newreq);
805}
Tom Josepha30c8d32018-03-22 02:15:03 +0530806
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700807/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
808 *
809 * @param[in] bus - The bus object used for lookups
810 * @param[in] params - The parameters for the channel
811 * @return The address and prefix if found
812 */
813auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530814{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700815 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
816}
Tom Josepha30c8d32018-03-22 02:15:03 +0530817
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700818/** @brief Reconfigures the IPv4 address info configured for the interface
819 *
820 * @param[in] bus - The bus object used for lookups
821 * @param[in] params - The parameters for the channel
822 * @param[in] address - The new address if specified
823 * @param[in] prefix - The new address prefix if specified
824 */
825void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
826 const std::optional<in_addr>& address,
827 std::optional<uint8_t> prefix)
828{
829 auto ifaddr = getIfAddr4(bus, params);
830 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530831 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700832 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530833 elog<InternalFailure>();
834 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700835 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
836 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530837 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700838 fallbackPrefix = ifaddr->prefix;
839 deleteObjectIfExists(bus, params.service, ifaddr->path);
840 }
841 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
842 prefix.value_or(fallbackPrefix));
843}
844
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700845template <int family>
846std::optional<IfNeigh<family>>
847 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
848 const typename AddrFamily<family>::addr& ip,
849 ObjectLookupCache& neighbors)
850{
851 const auto state =
852 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
853 Neighbor::State::Permanent);
854 for (const auto& [path, neighbor] : neighbors)
855 {
856 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
857 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
858 if (!neighIP)
859 {
860 continue;
861 }
862 if (!equal(*neighIP, ip))
863 {
864 continue;
865 }
866 if (state != std::get<std::string>(neighbor.at("State")))
867 {
868 continue;
869 }
870
871 IfNeigh<family> ret;
872 ret.path = path;
873 ret.ip = ip;
874 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
875 ret.mac = stringToMAC(macStr.c_str());
876 return std::move(ret);
877 }
878
879 return std::nullopt;
880}
881
882template <int family>
883void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
884 const typename AddrFamily<family>::addr& address,
885 const ether_addr& mac)
886{
887 auto newreq =
888 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
889 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
890 std::string macStr = ether_ntoa(&mac);
891 newreq.append(addrToString<family>(address), macStr);
892 bus.call_noreply(newreq);
893}
894
895/** @brief Sets the system wide value for the default gateway
896 *
897 * @param[in] bus - The bus object used for lookups
898 * @param[in] params - The parameters for the channel
899 * @param[in] gateway - Gateway address to apply
900 */
901template <int family>
902void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
903 const typename AddrFamily<family>::addr& address)
904{
905 // Save the old gateway MAC address if it exists so we can recreate it
906 auto gateway = getGatewayProperty<family>(bus, params);
907 std::optional<IfNeigh<family>> neighbor;
908 if (gateway)
909 {
910 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
911 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
912 }
913
914 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
915 AddrFamily<family>::propertyGateway,
916 addrToString<family>(address));
917
918 // Restore the gateway MAC if we had one
919 if (neighbor)
920 {
921 deleteObjectIfExists(bus, params.service, neighbor->path);
922 createNeighbor<family>(bus, params, address, neighbor->mac);
923 }
924}
925
926template <int family>
927std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
928 const ChannelParams& params,
929 ObjectLookupCache& neighbors)
930{
931 auto gateway = getGatewayProperty<family>(bus, params);
932 if (!gateway)
933 {
934 return std::nullopt;
935 }
936
937 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
938}
939
940template <int family>
941std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
942 const ChannelParams& params)
943{
944 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
945 return findGatewayNeighbor<family>(bus, params, neighbors);
946}
947
948template <int family>
949void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
950 const ChannelParams& params, const ether_addr& mac)
951{
952 auto gateway = getGatewayProperty<family>(bus, params);
953 if (!gateway)
954 {
955 log<level::ERR>("Tried to set Gateway MAC without Gateway");
956 elog<InternalFailure>();
957 }
958
959 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
960 auto neighbor =
961 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
962 if (neighbor)
963 {
964 deleteObjectIfExists(bus, params.service, neighbor->path);
965 }
966
967 createNeighbor<family>(bus, params, *gateway, mac);
968}
969
William A. Kennington III16064aa2019-04-13 17:44:53 -0700970/** @brief Deconfigures the IPv6 address info configured for the interface
971 *
972 * @param[in] bus - The bus object used for lookups
973 * @param[in] params - The parameters for the channel
974 * @param[in] idx - The address index to operate on
975 */
976void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
977 uint8_t idx)
978{
979 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
980 if (ifaddr)
981 {
982 deleteObjectIfExists(bus, params.service, ifaddr->path);
983 }
984}
985
986/** @brief Reconfigures the IPv6 address info configured for the interface
987 *
988 * @param[in] bus - The bus object used for lookups
989 * @param[in] params - The parameters for the channel
990 * @param[in] idx - The address index to operate on
991 * @param[in] address - The new address
992 * @param[in] prefix - The new address prefix
993 */
994void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
995 uint8_t idx, const in6_addr& address, uint8_t prefix)
996{
997 deconfigureIfAddr6(bus, params, idx);
998 createIfAddr<AF_INET6>(bus, params, address, prefix);
999}
1000
1001/** @brief Converts the AddressOrigin into an IPv6Source
1002 *
1003 * @param[in] origin - The DBus Address Origin to convert
1004 * @return The IPv6Source version of the origin
1005 */
1006IPv6Source originToSourceType(IP::AddressOrigin origin)
1007{
1008 switch (origin)
1009 {
1010 case IP::AddressOrigin::Static:
1011 return IPv6Source::Static;
1012 case IP::AddressOrigin::DHCP:
1013 return IPv6Source::DHCP;
1014 case IP::AddressOrigin::SLAAC:
1015 return IPv6Source::SLAAC;
1016 default:
1017 {
1018 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
1019 convertForMessage(origin);
1020 log<level::ERR>(
1021 "Invalid IP::AddressOrigin conversion to IPv6Source",
1022 entry("ORIGIN=%s", originStr.c_str()));
1023 elog<InternalFailure>();
1024 }
1025 }
1026}
1027
1028/** @brief Packs the IPMI message response with IPv6 address data
1029 *
1030 * @param[out] ret - The IPMI response payload to be packed
1031 * @param[in] channel - The channel id corresponding to an ethernet interface
1032 * @param[in] set - The set selector for determining address index
1033 * @param[in] origins - Set of valid origins for address filtering
1034 */
1035void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
1036 const std::unordered_set<IP::AddressOrigin>& origins)
1037{
1038 auto source = IPv6Source::Static;
1039 bool enabled = false;
1040 in6_addr addr{};
1041 uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
1042 auto status = IPv6AddressStatus::Disabled;
1043
1044 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
1045 if (ifaddr)
1046 {
1047 source = originToSourceType(ifaddr->origin);
1048 enabled = true;
1049 addr = ifaddr->address;
1050 prefix = ifaddr->prefix;
1051 status = IPv6AddressStatus::Active;
1052 }
1053
1054 ret.pack(set);
1055 ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled);
1056 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
1057 ret.pack(prefix);
1058 ret.pack(static_cast<uint8_t>(status));
1059}
1060
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001061/** @brief Gets the vlan ID configured on the interface
1062 *
1063 * @param[in] bus - The bus object used for lookups
1064 * @param[in] params - The parameters for the channel
1065 * @return VLAN id or the standard 0 for no VLAN
1066 */
1067uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
1068{
1069 // VLAN devices will always have a separate logical object
1070 if (params.ifPath == params.logicalPath)
1071 {
1072 return 0;
1073 }
1074
1075 auto vlan = std::get<uint32_t>(getDbusProperty(
1076 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
1077 if ((vlan & VLAN_VALUE_MASK) != vlan)
1078 {
1079 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
1080 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +05301081 elog<InternalFailure>();
1082 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001083 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +05301084}
1085
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001086/** @brief Deletes all of the possible configuration parameters for a channel
1087 *
1088 * @param[in] bus - The bus object used for lookups
1089 * @param[in] params - The parameters for the channel
1090 */
1091void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001092{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001093 // Delete all objects associated with the interface
1094 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
1095 "GetSubTree");
1096 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
1097 auto objreply = bus.call(objreq);
1098 ObjectTree objs;
1099 objreply.read(objs);
1100 for (const auto& [path, impls] : objs)
1101 {
1102 if (path.find(params.ifname) == path.npos)
1103 {
1104 continue;
1105 }
1106 for (const auto& [service, intfs] : impls)
1107 {
1108 deleteObjectIfExists(bus, service, path);
1109 }
1110 // Update params to reflect the deletion of vlan
1111 if (path == params.logicalPath)
1112 {
1113 params.logicalPath = params.ifPath;
1114 }
1115 }
1116
1117 // Clear out any settings on the lower physical interface
1118 setDHCPProperty(bus, params, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001119}
1120
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001121/** @brief Creates a new VLAN on the specified interface
1122 *
1123 * @param[in] bus - The bus object used for lookups
1124 * @param[in] params - The parameters for the channel
1125 * @param[in] vlan - The id of the new vlan
1126 */
1127void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +05301128{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001129 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301130 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001131 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301132 }
1133
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001134 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
1135 INTF_VLAN_CREATE, "VLAN");
1136 req.append(params.ifname, static_cast<uint32_t>(vlan));
1137 auto reply = bus.call(req);
1138 sdbusplus::message::object_path newPath;
1139 reply.read(newPath);
1140 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301141}
1142
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001143/** @brief Performs the necessary reconfiguration to change the VLAN
1144 *
1145 * @param[in] bus - The bus object used for lookups
1146 * @param[in] params - The parameters for the channel
1147 * @param[in] vlan - The new vlan id to use
1148 */
1149void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
1150 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001151{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001152 // Unfortunatetly we don't have built-in functions to migrate our interface
1153 // customizations to new VLAN interfaces, or have some kind of decoupling.
1154 // We therefore must retain all of our old information, setup the new VLAN
1155 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +08001156
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001157 // Save info from the old logical interface
1158 ObjectLookupCache ips(bus, params, INTF_IP);
1159 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001160 std::vector<IfAddr<AF_INET6>> ifaddrs6;
1161 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
1162 {
1163 auto ifaddr6 =
1164 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
1165 if (!ifaddr6)
1166 {
1167 break;
1168 }
1169 ifaddrs6.push_back(std::move(*ifaddr6));
1170 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001171 auto dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001172 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1173 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001174 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001175
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001176 deconfigureChannel(bus, params);
1177 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001178
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001179 // Re-establish the saved settings
1180 setDHCPProperty(bus, params, dhcp);
1181 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001182 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001183 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001184 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001185 for (const auto& ifaddr6 : ifaddrs6)
1186 {
1187 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
1188 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001189 if (neighbor4)
1190 {
1191 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
1192 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001193 if (neighbor6)
1194 {
1195 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
1196 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001197}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001198
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001199/** @brief Turns a prefix into a netmask
1200 *
1201 * @param[in] prefix - The prefix length
1202 * @return The netmask
1203 */
1204in_addr prefixToNetmask(uint8_t prefix)
1205{
1206 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001207 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001208 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
1209 elog<InternalFailure>();
1210 }
1211 if (prefix == 0)
1212 {
1213 // Avoids 32-bit lshift by 32 UB
1214 return {};
1215 }
1216 return {htobe32(~UINT32_C(0) << (32 - prefix))};
1217}
1218
1219/** @brief Turns a a netmask into a prefix length
1220 *
1221 * @param[in] netmask - The netmask in byte form
1222 * @return The prefix length
1223 */
1224uint8_t netmaskToPrefix(in_addr netmask)
1225{
1226 uint32_t x = be32toh(netmask.s_addr);
1227 if ((~x & (~x + 1)) != 0)
1228 {
1229 char maskStr[INET_ADDRSTRLEN];
1230 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
1231 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
1232 elog<InternalFailure>();
1233 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -08001234 return static_cast<bool>(x)
1235 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
1236 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001237}
1238
1239// We need to store this value so it can be returned to the client
1240// It is volatile so safe to store in daemon memory.
1241static std::unordered_map<uint8_t, SetStatus> setStatus;
1242
1243// Until we have good support for fixed versions of IPMI tool
1244// we need to return the VLAN id for disabled VLANs. The value is only
1245// used for verification that a disable operation succeeded and will only
1246// be sent if our system indicates that vlans are disabled.
1247static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
1248
1249/** @brief Gets the set status for the channel if it exists
1250 * Otherise populates and returns the default value.
1251 *
1252 * @param[in] channel - The channel id corresponding to an ethernet interface
1253 * @return A reference to the SetStatus for the channel
1254 */
1255SetStatus& getSetStatus(uint8_t channel)
1256{
1257 auto it = setStatus.find(channel);
1258 if (it != setStatus.end())
1259 {
1260 return it->second;
1261 }
1262 return setStatus[channel] = SetStatus::Complete;
1263}
1264
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001265/**
1266 * Define placeholder command handlers for the OEM Extension bytes for the Set
1267 * LAN Configuration Parameters and Get LAN Configuration Parameters
1268 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
1269 * functions below to be overridden.
1270 * To create handlers for your own proprietary command set:
1271 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
1272 * recipe
1273 * Create C++ file(s) that define IPMI handler functions matching the
1274 * function names below (i.e. setLanOem). The default name for the
1275 * transport IPMI commands is transporthandler_oem.cpp.
1276 * Add:
1277 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
1278 * Create a do_compile_prepend()/do_install_append method in your
1279 * bbappend file to copy the file to the build directory.
1280 * Add:
1281 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
1282 * # Copy the "strong" functions into the working directory, overriding the
1283 * # placeholder functions.
1284 * do_compile_prepend(){
1285 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
1286 * }
1287 *
1288 * # Clean up after complilation has completed
1289 * do_install_append(){
1290 * rm -f ${S}/transporthandler_oem.cpp
1291 * }
1292 *
1293 */
1294
1295/**
1296 * Define the placeholder OEM commands as having weak linkage. Create
1297 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
1298 * file. The functions defined there must not have the "weak" attribute
1299 * applied to them.
1300 */
1301RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1302 __attribute__((weak));
1303RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1304 uint8_t set, uint8_t block)
1305 __attribute__((weak));
1306
1307RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1308{
1309 req.trailingOk = true;
1310 return response(ccParamNotSupported);
1311}
1312
1313RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1314 uint8_t set, uint8_t block)
1315{
1316 return response(ccParamNotSupported);
1317}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301318/**
1319 * @brief is MAC address valid.
1320 *
1321 * This function checks whether the MAC address is valid or not.
1322 *
1323 * @param[in] mac - MAC address.
1324 * @return true if MAC address is valid else retun false.
1325 **/
1326bool isValidMACAddress(const ether_addr& mac)
1327{
1328 // check if mac address is empty
1329 if (equal(mac, ether_addr{}))
1330 {
1331 return false;
1332 }
1333 // we accept only unicast MAC addresses and same thing has been checked in
1334 // phosphor-network layer. If the least significant bit of the first octet
1335 // is set to 1, it is multicast MAC else it is unicast MAC address.
1336 if (mac.ether_addr_octet[0] & 1)
1337 {
1338 return false;
1339 }
1340 return true;
1341}
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001342
vijayabharathix shettycc769252020-02-27 17:52:20 +00001343RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1344 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001345{
vijayabharathix shettycc769252020-02-27 17:52:20 +00001346 const uint8_t channel = convertCurrentChannelNum(
1347 static_cast<uint8_t>(channelBits), ctx->channel);
1348 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001349 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001350 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001351 req.trailingOk = true;
1352 return responseInvalidFieldRequest();
1353 }
1354
1355 switch (static_cast<LanParam>(parameter))
1356 {
1357 case LanParam::SetStatus:
1358 {
1359 uint2_t flag;
1360 uint6_t rsvd;
1361 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1362 {
1363 return responseReqDataLenInvalid();
1364 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001365 if (rsvd)
1366 {
1367 return responseInvalidFieldRequest();
1368 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001369 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1370 switch (status)
1371 {
1372 case SetStatus::Complete:
1373 {
1374 getSetStatus(channel) = status;
1375 return responseSuccess();
1376 }
1377 case SetStatus::InProgress:
1378 {
1379 auto& storedStatus = getSetStatus(channel);
1380 if (storedStatus == SetStatus::InProgress)
1381 {
1382 return response(ccParamSetLocked);
1383 }
1384 storedStatus = status;
1385 return responseSuccess();
1386 }
1387 case SetStatus::Commit:
1388 if (getSetStatus(channel) != SetStatus::InProgress)
1389 {
1390 return responseInvalidFieldRequest();
1391 }
1392 return responseSuccess();
1393 }
1394 return response(ccParamNotSupported);
1395 }
1396 case LanParam::AuthSupport:
1397 {
1398 req.trailingOk = true;
1399 return response(ccParamReadOnly);
1400 }
1401 case LanParam::AuthEnables:
1402 {
1403 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001404 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001405 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001406 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001407 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001408 if (channelCall<getDHCPProperty>(channel))
1409 {
1410 return responseCommandNotAvailable();
1411 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001412 in_addr ip;
1413 std::array<uint8_t, sizeof(ip)> bytes;
1414 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1415 {
1416 return responseReqDataLenInvalid();
1417 }
1418 copyInto(ip, bytes);
1419 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1420 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301421 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001422 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301423 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001424 uint4_t flag;
1425 uint4_t rsvd;
1426 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1427 {
1428 return responseReqDataLenInvalid();
1429 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001430 if (rsvd)
1431 {
1432 return responseInvalidFieldRequest();
1433 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001434 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1435 {
1436 case IPSrc::DHCP:
1437 {
1438 channelCall<setDHCPProperty>(channel, true);
1439 return responseSuccess();
1440 }
1441 case IPSrc::Unspecified:
1442 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001443 {
1444 channelCall<setDHCPProperty>(channel, false);
1445 return responseSuccess();
1446 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +05301447 case IPSrc::BIOS:
1448 case IPSrc::BMC:
1449 {
1450 return responseInvalidFieldRequest();
1451 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001452 }
1453 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301454 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001455 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301456 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001457 ether_addr mac;
1458 std::array<uint8_t, sizeof(mac)> bytes;
1459 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301460 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001461 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301462 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001463 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301464
1465 if (!isValidMACAddress(mac))
1466 {
1467 return responseInvalidFieldRequest();
1468 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001469 channelCall<setMACProperty>(channel, mac);
1470 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301471 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001472 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301473 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001474 if (channelCall<getDHCPProperty>(channel))
1475 {
1476 return responseCommandNotAvailable();
1477 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001478 in_addr netmask;
1479 std::array<uint8_t, sizeof(netmask)> bytes;
1480 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301481 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001482 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301483 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001484 copyInto(netmask, bytes);
1485 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1486 netmaskToPrefix(netmask));
1487 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301488 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001489 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301490 {
Johnathan Mantey930104a2019-12-17 09:18:34 -08001491 if (channelCall<getDHCPProperty>(channel))
1492 {
1493 return responseCommandNotAvailable();
1494 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001495 in_addr gateway;
1496 std::array<uint8_t, sizeof(gateway)> bytes;
1497 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1498 {
1499 return responseReqDataLenInvalid();
1500 }
1501 copyInto(gateway, bytes);
1502 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1503 return responseSuccess();
1504 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001505 case LanParam::Gateway1MAC:
1506 {
1507 ether_addr gatewayMAC;
1508 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1509 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1510 {
1511 return responseReqDataLenInvalid();
1512 }
1513 copyInto(gatewayMAC, bytes);
1514 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1515 return responseSuccess();
1516 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001517 case LanParam::VLANId:
1518 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301519 uint12_t vlanData = 0;
1520 uint3_t reserved = 0;
1521 bool vlanEnable = 0;
1522
1523 if (req.unpack(vlanData) || req.unpack(reserved) ||
1524 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001525 {
1526 return responseReqDataLenInvalid();
1527 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301528
1529 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001530 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301531 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001532 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301533
1534 uint16_t vlan = static_cast<uint16_t>(vlanData);
1535
1536 if (!vlanEnable)
1537 {
1538 lastDisabledVlan[channel] = vlan;
1539 vlan = 0;
1540 }
1541 channelCall<reconfigureVLAN>(channel, vlan);
1542
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001543 return responseSuccess();
1544 }
1545 case LanParam::CiphersuiteSupport:
1546 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001547 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001548 {
1549 req.trailingOk = true;
1550 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301551 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001552 case LanParam::IPFamilyEnables:
1553 {
1554 uint8_t enables;
1555 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1556 {
1557 return responseReqDataLenInvalid();
1558 }
1559 switch (static_cast<IPFamilyEnables>(enables))
1560 {
1561 case IPFamilyEnables::DualStack:
1562 return responseSuccess();
1563 case IPFamilyEnables::IPv4Only:
1564 case IPFamilyEnables::IPv6Only:
1565 return response(ccParamNotSupported);
1566 }
1567 return response(ccParamNotSupported);
1568 }
1569 case LanParam::IPv6Status:
1570 {
1571 req.trailingOk = true;
1572 return response(ccParamReadOnly);
1573 }
1574 case LanParam::IPv6StaticAddresses:
1575 {
1576 uint8_t set;
1577 uint7_t rsvd;
1578 bool enabled;
1579 in6_addr ip;
1580 std::array<uint8_t, sizeof(ip)> ipbytes;
1581 uint8_t prefix;
1582 uint8_t status;
1583 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1584 !req.fullyUnpacked())
1585 {
1586 return responseReqDataLenInvalid();
1587 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001588 if (rsvd)
1589 {
1590 return responseInvalidFieldRequest();
1591 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001592 copyInto(ip, ipbytes);
1593 if (enabled)
1594 {
1595 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1596 }
1597 else
1598 {
1599 channelCall<deconfigureIfAddr6>(channel, set);
1600 }
1601 return responseSuccess();
1602 }
1603 case LanParam::IPv6DynamicAddresses:
1604 {
1605 req.trailingOk = true;
1606 return response(ccParamReadOnly);
1607 }
1608 case LanParam::IPv6RouterControl:
1609 {
1610 std::bitset<8> control;
1611 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1612 {
1613 return responseReqDataLenInvalid();
1614 }
1615 std::bitset<8> expected;
1616 if (channelCall<getDHCPProperty>(channel))
1617 {
1618 expected[IPv6RouterControlFlag::Dynamic] = 1;
1619 }
1620 else
1621 {
1622 expected[IPv6RouterControlFlag::Static] = 1;
1623 }
1624 if (expected != control)
1625 {
1626 return responseInvalidFieldRequest();
1627 }
1628 return responseSuccess();
1629 }
1630 case LanParam::IPv6StaticRouter1IP:
1631 {
1632 in6_addr gateway;
1633 std::array<uint8_t, sizeof(gateway)> bytes;
1634 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1635 {
1636 return responseReqDataLenInvalid();
1637 }
1638 copyInto(gateway, bytes);
1639 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1640 return responseSuccess();
1641 }
1642 case LanParam::IPv6StaticRouter1MAC:
1643 {
1644 ether_addr mac;
1645 std::array<uint8_t, sizeof(mac)> bytes;
1646 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1647 {
1648 return responseReqDataLenInvalid();
1649 }
1650 copyInto(mac, bytes);
1651 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1652 return responseSuccess();
1653 }
1654 case LanParam::IPv6StaticRouter1PrefixLength:
1655 {
1656 uint8_t prefix;
1657 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1658 {
1659 return responseReqDataLenInvalid();
1660 }
1661 if (prefix != 0)
1662 {
1663 return responseInvalidFieldRequest();
1664 }
1665 return responseSuccess();
1666 }
1667 case LanParam::IPv6StaticRouter1PrefixValue:
1668 {
1669 std::array<uint8_t, sizeof(in6_addr)> bytes;
1670 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1671 {
1672 return responseReqDataLenInvalid();
1673 }
1674 // Accept any prefix value since our prefix length has to be 0
1675 return responseSuccess();
1676 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001677 case LanParam::cipherSuitePrivilegeLevels:
1678 {
1679 uint8_t reserved;
1680 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1681
1682 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1683 {
1684 return responseReqDataLenInvalid();
1685 }
1686
1687 if (reserved)
1688 {
1689 return responseInvalidFieldRequest();
1690 }
1691
1692 uint8_t resp =
1693 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1694 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1695 if (!resp)
1696 {
1697 return responseSuccess();
1698 }
1699 else
1700 {
1701 req.trailingOk = true;
1702 return response(resp);
1703 }
1704 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301705 }
vishwa1eaea4f2016-02-26 11:57:40 -06001706
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001707 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1708 {
1709 return setLanOem(channel, parameter, req);
1710 }
1711
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001712 req.trailingOk = true;
1713 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001714}
1715
vijayabharathix shettycc769252020-02-27 17:52:20 +00001716RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1717 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001718 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301719{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001720 message::Payload ret;
1721 constexpr uint8_t current_revision = 0x11;
1722 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001723
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001724 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301725 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001726 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301727 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001728
vijayabharathix shettycc769252020-02-27 17:52:20 +00001729 const uint8_t channel = convertCurrentChannelNum(
1730 static_cast<uint8_t>(channelBits), ctx->channel);
1731 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001732 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001733 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001734 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001735 }
1736
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001737 static std::vector<uint8_t> cipherList;
1738 static bool listInit = false;
1739 if (!listInit)
1740 {
1741 try
1742 {
1743 cipherList = cipher::getCipherList();
1744 listInit = true;
1745 }
1746 catch (const std::exception& e)
1747 {
1748 }
1749 }
1750
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001751 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301752 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001753 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301754 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001755 SetStatus status;
1756 try
1757 {
1758 status = setStatus.at(channel);
1759 }
1760 catch (const std::out_of_range&)
1761 {
1762 status = SetStatus::Complete;
1763 }
1764 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1765 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301766 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001767 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301768 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001769 std::bitset<6> support;
1770 ret.pack(support, uint2_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::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001774 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001775 std::bitset<6> enables;
1776 ret.pack(enables, uint2_t{}); // Callback
1777 ret.pack(enables, uint2_t{}); // User
1778 ret.pack(enables, uint2_t{}); // Operator
1779 ret.pack(enables, uint2_t{}); // Admin
1780 ret.pack(enables, uint2_t{}); // OEM
1781 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001782 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001783 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001784 {
1785 auto ifaddr = channelCall<getIfAddr4>(channel);
1786 in_addr addr{};
1787 if (ifaddr)
1788 {
1789 addr = ifaddr->address;
1790 }
1791 ret.pack(dataRef(addr));
1792 return responseSuccess(std::move(ret));
1793 }
1794 case LanParam::IPSrc:
1795 {
1796 auto src = IPSrc::Static;
1797 if (channelCall<getDHCPProperty>(channel))
1798 {
1799 src = IPSrc::DHCP;
1800 }
1801 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1802 return responseSuccess(std::move(ret));
1803 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001804 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001805 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001806 ether_addr mac = channelCall<getMACProperty>(channel);
1807 ret.pack(dataRef(mac));
1808 return responseSuccess(std::move(ret));
1809 }
1810 case LanParam::SubnetMask:
1811 {
1812 auto ifaddr = channelCall<getIfAddr4>(channel);
1813 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1814 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301815 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001816 prefix = ifaddr->prefix;
1817 }
1818 in_addr netmask = prefixToNetmask(prefix);
1819 ret.pack(dataRef(netmask));
1820 return responseSuccess(std::move(ret));
1821 }
1822 case LanParam::Gateway1:
1823 {
1824 auto gateway =
1825 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1826 in_addr{});
1827 ret.pack(dataRef(gateway));
1828 return responseSuccess(std::move(ret));
1829 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001830 case LanParam::Gateway1MAC:
1831 {
1832 ether_addr mac{};
1833 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1834 if (neighbor)
1835 {
1836 mac = neighbor->mac;
1837 }
1838 ret.pack(dataRef(mac));
1839 return responseSuccess(std::move(ret));
1840 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001841 case LanParam::VLANId:
1842 {
1843 uint16_t vlan = channelCall<getVLANProperty>(channel);
1844 if (vlan != 0)
1845 {
1846 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301847 }
1848 else
1849 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001850 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301851 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001852 ret.pack(vlan);
1853 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001854 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001855 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001856 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001857 if (getChannelSessionSupport(channel) ==
1858 EChannelSessSupported::none)
1859 {
1860 return responseInvalidFieldRequest();
1861 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001862 if (!listInit)
1863 {
1864 return responseUnspecifiedError();
1865 }
1866 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1867 return responseSuccess(std::move(ret));
1868 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001869 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001870 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001871 if (getChannelSessionSupport(channel) ==
1872 EChannelSessSupported::none)
1873 {
1874 return responseInvalidFieldRequest();
1875 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001876 if (!listInit)
1877 {
1878 return responseUnspecifiedError();
1879 }
1880 ret.pack(cipherList);
1881 return responseSuccess(std::move(ret));
1882 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001883 case LanParam::IPFamilySupport:
1884 {
1885 std::bitset<8> support;
1886 support[IPFamilySupportFlag::IPv6Only] = 0;
1887 support[IPFamilySupportFlag::DualStack] = 1;
1888 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1889 ret.pack(support);
1890 return responseSuccess(std::move(ret));
1891 }
1892 case LanParam::IPFamilyEnables:
1893 {
1894 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1895 return responseSuccess(std::move(ret));
1896 }
1897 case LanParam::IPv6Status:
1898 {
1899 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1900 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1901 std::bitset<8> support;
1902 support[IPv6StatusFlag::DHCP] = 1;
1903 support[IPv6StatusFlag::SLAAC] = 1;
1904 ret.pack(support);
1905 return responseSuccess(std::move(ret));
1906 }
1907 case LanParam::IPv6StaticAddresses:
1908 {
1909 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1910 {
1911 return responseParmOutOfRange();
1912 }
1913 getLanIPv6Address(ret, channel, set, originsV6Static);
1914 return responseSuccess(std::move(ret));
1915 }
1916 case LanParam::IPv6DynamicAddresses:
1917 {
1918 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1919 {
1920 return responseParmOutOfRange();
1921 }
1922 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1923 return responseSuccess(std::move(ret));
1924 }
1925 case LanParam::IPv6RouterControl:
1926 {
1927 std::bitset<8> control;
1928 if (channelCall<getDHCPProperty>(channel))
1929 {
1930 control[IPv6RouterControlFlag::Dynamic] = 1;
1931 }
1932 else
1933 {
1934 control[IPv6RouterControlFlag::Static] = 1;
1935 }
1936 ret.pack(control);
1937 return responseSuccess(std::move(ret));
1938 }
1939 case LanParam::IPv6StaticRouter1IP:
1940 {
1941 in6_addr gateway{};
1942 if (!channelCall<getDHCPProperty>(channel))
1943 {
1944 gateway =
1945 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1946 in6_addr{});
1947 }
1948 ret.pack(dataRef(gateway));
1949 return responseSuccess(std::move(ret));
1950 }
1951 case LanParam::IPv6StaticRouter1MAC:
1952 {
1953 ether_addr mac{};
1954 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1955 if (neighbor)
1956 {
1957 mac = neighbor->mac;
1958 }
1959 ret.pack(dataRef(mac));
1960 return responseSuccess(std::move(ret));
1961 }
1962 case LanParam::IPv6StaticRouter1PrefixLength:
1963 {
1964 ret.pack(UINT8_C(0));
1965 return responseSuccess(std::move(ret));
1966 }
1967 case LanParam::IPv6StaticRouter1PrefixValue:
1968 {
1969 in6_addr prefix{};
1970 ret.pack(dataRef(prefix));
1971 return responseSuccess(std::move(ret));
1972 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001973 case LanParam::cipherSuitePrivilegeLevels:
1974 {
1975 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1976
1977 uint8_t resp =
1978 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1979 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1980 if (!resp)
1981 {
1982 constexpr uint8_t reserved1 = 0x00;
1983 ret.pack(reserved1, csPrivilegeLevels);
1984 return responseSuccess(std::move(ret));
1985 }
1986 else
1987 {
1988 return response(resp);
1989 }
1990 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001991 }
1992
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001993 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1994 {
1995 return getLanOem(channel, parameter, set, block);
1996 }
1997
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001998 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001999}
2000
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002001} // namespace transport
2002} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302003
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002004void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302005
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002006void register_netfn_transport_functions()
2007{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002008 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2009 ipmi::transport::cmdSetLanConfigParameters,
2010 ipmi::Privilege::Admin, ipmi::transport::setLan);
2011 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2012 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08002013 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002014}