blob: e48137f2e1d3b6bb04af41cd3a61f70912b5429f [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>
Johnathan Mantey65265362019-11-14 11:24:19 -080034#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070035#include <xyz/openbmc_project/Network/IP/server.hpp>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070036#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070037
William A. Kennington IIIc514d872019-04-06 18:19:38 -070038using phosphor::logging::commit;
39using phosphor::logging::elog;
40using phosphor::logging::entry;
41using phosphor::logging::level;
42using phosphor::logging::log;
43using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Johnathan Mantey65265362019-11-14 11:24:19 -080044using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070045using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070046using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070047
Johnathan Manteyaffadb52019-10-07 10:13:53 -070048namespace cipher
49{
50
51std::vector<uint8_t> getCipherList()
52{
53 std::vector<uint8_t> cipherList;
54
55 std::ifstream jsonFile(cipher::configFile);
56 if (!jsonFile.is_open())
57 {
58 log<level::ERR>("Channel Cipher suites file not found");
59 elog<InternalFailure>();
60 }
61
62 auto data = Json::parse(jsonFile, nullptr, false);
63 if (data.is_discarded())
64 {
65 log<level::ERR>("Parsing channel cipher suites JSON failed");
66 elog<InternalFailure>();
67 }
68
69 // Byte 1 is reserved
70 cipherList.push_back(0x00);
71
72 for (const auto& record : data)
73 {
74 cipherList.push_back(record.value(cipher, 0));
75 }
76
77 return cipherList;
78}
79} // namespace cipher
80
81namespace ipmi
82{
83namespace transport
84{
85
William A. Kennington IIIc514d872019-04-06 18:19:38 -070086// LAN Handler specific response codes
87constexpr Cc ccParamNotSupported = 0x80;
88constexpr Cc ccParamSetLocked = 0x81;
89constexpr Cc ccParamReadOnly = 0x82;
90
91// VLANs are a 12-bit value
92constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
93constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
94
William A. Kennington III16064aa2019-04-13 17:44:53 -070095// Arbitrary v6 Address Limits to prevent too much output in ipmitool
96constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
97constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
98
William A. Kennington IIIc514d872019-04-06 18:19:38 -070099// D-Bus Network Daemon definitions
100constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
101constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
102
103constexpr auto INTF_SYSTEMCONFIG =
104 "xyz.openbmc_project.Network.SystemConfiguration";
105constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
106constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
107constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
108constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700109constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
110constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
111 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700112constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
113constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
114
115/** @brief Generic paramters for different address families */
116template <int family>
117struct AddrFamily
118{
119};
120
121/** @brief Parameter specialization for IPv4 */
122template <>
123struct AddrFamily<AF_INET>
124{
125 using addr = in_addr;
126 static constexpr auto protocol = IP::Protocol::IPv4;
127 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
128 static constexpr uint8_t defaultPrefix = 32;
129 static constexpr char propertyGateway[] = "DefaultGateway";
130};
131
William A. Kennington III16064aa2019-04-13 17:44:53 -0700132/** @brief Parameter specialization for IPv6 */
133template <>
134struct AddrFamily<AF_INET6>
135{
136 using addr = in6_addr;
137 static constexpr auto protocol = IP::Protocol::IPv6;
138 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
139 static constexpr uint8_t defaultPrefix = 128;
140 static constexpr char propertyGateway[] = "DefaultGateway6";
141};
142
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700143/** @brief Valid address origins for IPv4 */
144const std::unordered_set<IP::AddressOrigin> originsV4 = {
145 IP::AddressOrigin::Static,
146 IP::AddressOrigin::DHCP,
147};
148
William A. Kennington III16064aa2019-04-13 17:44:53 -0700149/** @brief Valid address origins for IPv6 */
150const std::unordered_set<IP::AddressOrigin> originsV6Static = {
151 IP::AddressOrigin::Static};
152const std::unordered_set<IP::AddressOrigin> originsV6Dynamic = {
153 IP::AddressOrigin::DHCP,
154 IP::AddressOrigin::SLAAC,
155};
156
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700157/** @brief Interface IP Address configuration parameters */
158template <int family>
159struct IfAddr
160{
161 std::string path;
162 typename AddrFamily<family>::addr address;
163 IP::AddressOrigin origin;
164 uint8_t prefix;
165};
166
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700167/** @brief Interface Neighbor configuration parameters */
168template <int family>
169struct IfNeigh
170{
171 std::string path;
172 typename AddrFamily<family>::addr ip;
173 ether_addr mac;
174};
175
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700176/** @brief IPMI LAN Parameters */
177enum class LanParam : uint8_t
178{
179 SetStatus = 0,
180 AuthSupport = 1,
181 AuthEnables = 2,
182 IP = 3,
183 IPSrc = 4,
184 MAC = 5,
185 SubnetMask = 6,
186 Gateway1 = 12,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700187 Gateway1MAC = 13,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700188 VLANId = 20,
189 CiphersuiteSupport = 22,
190 CiphersuiteEntries = 23,
jayaprakash Mutyalab741b992019-12-02 17:29:09 +0000191 cipherSuitePrivilegeLevels = 24,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700192 IPFamilySupport = 50,
193 IPFamilyEnables = 51,
194 IPv6Status = 55,
195 IPv6StaticAddresses = 56,
196 IPv6DynamicAddresses = 59,
197 IPv6RouterControl = 64,
198 IPv6StaticRouter1IP = 65,
199 IPv6StaticRouter1MAC = 66,
200 IPv6StaticRouter1PrefixLength = 67,
201 IPv6StaticRouter1PrefixValue = 68,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700202};
203
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700204static constexpr uint8_t oemCmdStart = 192;
205static constexpr uint8_t oemCmdEnd = 255;
206
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700207/** @brief IPMI IP Origin Types */
208enum class IPSrc : uint8_t
209{
210 Unspecified = 0,
211 Static = 1,
212 DHCP = 2,
213 BIOS = 3,
214 BMC = 4,
215};
216
217/** @brief IPMI Set Status */
218enum class SetStatus : uint8_t
219{
220 Complete = 0,
221 InProgress = 1,
222 Commit = 2,
223};
224
William A. Kennington III16064aa2019-04-13 17:44:53 -0700225/** @brief IPMI Family Suport Bits */
226namespace IPFamilySupportFlag
227{
228constexpr uint8_t IPv6Only = 0;
229constexpr uint8_t DualStack = 1;
230constexpr uint8_t IPv6Alerts = 2;
231} // namespace IPFamilySupportFlag
232
233/** @brief IPMI IPFamily Enables Flag */
234enum class IPFamilyEnables : uint8_t
235{
236 IPv4Only = 0,
237 IPv6Only = 1,
238 DualStack = 2,
239};
240
241/** @brief IPMI IPv6 Dyanmic Status Bits */
242namespace IPv6StatusFlag
243{
244constexpr uint8_t DHCP = 0;
245constexpr uint8_t SLAAC = 1;
246}; // namespace IPv6StatusFlag
247
248/** @brief IPMI IPv6 Source */
249enum class IPv6Source : uint8_t
250{
251 Static = 0,
252 SLAAC = 1,
253 DHCP = 2,
254};
255
256/** @brief IPMI IPv6 Address Status */
257enum class IPv6AddressStatus : uint8_t
258{
259 Active = 0,
260 Disabled = 1,
261};
262
263namespace IPv6RouterControlFlag
264{
265constexpr uint8_t Static = 0;
266constexpr uint8_t Dynamic = 1;
267}; // namespace IPv6RouterControlFlag
268
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700269/** @brief A trivial helper used to determine if two PODs are equal
270 *
271 * @params[in] a - The first object to compare
272 * @params[in] b - The second object to compare
273 * @return True if the objects are the same bytewise
274 */
275template <typename T>
276bool equal(const T& a, const T& b)
277{
278 static_assert(std::is_trivially_copyable_v<T>);
279 return std::memcmp(&a, &b, sizeof(T)) == 0;
280}
281
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700282/** @brief Copies bytes from an array into a trivially copyable container
283 *
284 * @params[out] t - The container receiving the data
285 * @params[in] bytes - The data to copy
286 */
287template <size_t N, typename T>
288void copyInto(T& t, const std::array<uint8_t, N>& bytes)
289{
290 static_assert(std::is_trivially_copyable_v<T>);
291 static_assert(N == sizeof(T));
292 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800293}
294
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700295/** @brief Gets a generic view of the bytes in the input container
296 *
297 * @params[in] t - The data to reference
298 * @return A string_view referencing the bytes in the container
299 */
300template <typename T>
301std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600302{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700303 static_assert(std::is_trivially_copyable_v<T>);
304 return {reinterpret_cast<const char*>(&t), sizeof(T)};
305}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530306
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700307/** @brief The dbus parameters for the interface corresponding to a channel
308 * This helps reduce the number of mapper lookups we need for each
309 * query and simplifies finding the VLAN interface if needed.
310 */
311struct ChannelParams
312{
313 /** @brief The channel ID */
314 int id;
315 /** @brief channel name for the interface */
316 std::string ifname;
317 /** @brief Name of the service on the bus */
318 std::string service;
319 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
320 std::string ifPath;
321 /** @brief Logical adapter path used for address assignment */
322 std::string logicalPath;
323};
324
325/** @brief Determines the ethernet interface name corresponding to a channel
326 * Tries to map a VLAN object first so that the address information
327 * is accurate. Otherwise it gets the standard ethernet interface.
328 *
329 * @param[in] bus - The bus object used for lookups
330 * @param[in] channel - The channel id corresponding to an ethernet interface
331 * @return Ethernet interface service and object path if it exists
332 */
333std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
334 uint8_t channel)
335{
336 auto ifname = getChannelName(channel);
337 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800338 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700339 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800340 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800341
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700342 // Enumerate all VLAN + ETHERNET interfaces
343 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
344 "GetSubTree");
345 req.append(PATH_ROOT, 0,
346 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
347 auto reply = bus.call(req);
348 ObjectTree objs;
349 reply.read(objs);
350
351 ChannelParams params;
352 for (const auto& [path, impls] : objs)
353 {
354 if (path.find(ifname) == path.npos)
355 {
356 continue;
357 }
358 for (const auto& [service, intfs] : impls)
359 {
360 bool vlan = false;
361 bool ethernet = false;
362 for (const auto& intf : intfs)
363 {
364 if (intf == INTF_VLAN)
365 {
366 vlan = true;
367 }
368 else if (intf == INTF_ETHERNET)
369 {
370 ethernet = true;
371 }
372 }
373 if (params.service.empty() && (vlan || ethernet))
374 {
375 params.service = service;
376 }
377 if (params.ifPath.empty() && !vlan && ethernet)
378 {
379 params.ifPath = path;
380 }
381 if (params.logicalPath.empty() && vlan)
382 {
383 params.logicalPath = path;
384 }
385 }
386 }
387
388 // We must have a path for the underlying interface
389 if (params.ifPath.empty())
390 {
391 return std::nullopt;
392 }
393 // We don't have a VLAN so the logical path is the same
394 if (params.logicalPath.empty())
395 {
396 params.logicalPath = params.ifPath;
397 }
398
399 params.id = channel;
400 params.ifname = std::move(ifname);
401 return std::move(params);
402}
403
404/** @brief A trivial helper around maybeGetChannelParams() that throws an
405 * exception when it is unable to acquire parameters for the channel.
406 *
407 * @param[in] bus - The bus object used for lookups
408 * @param[in] channel - The channel id corresponding to an ethernet interface
409 * @return Ethernet interface service and object path
410 */
411ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
412{
413 auto params = maybeGetChannelParams(bus, channel);
414 if (!params)
415 {
416 log<level::ERR>("Failed to get channel params",
417 entry("CHANNEL=%" PRIu8, channel));
418 elog<InternalFailure>();
419 }
420 return std::move(*params);
421}
422
423/** @brief Wraps the phosphor logging method to insert some additional metadata
424 *
425 * @param[in] params - The parameters for the channel
426 * ...
427 */
428template <auto level, typename... Args>
429auto logWithChannel(const ChannelParams& params, Args&&... args)
430{
431 return log<level>(std::forward<Args>(args)...,
432 entry("CHANNEL=%d", params.id),
433 entry("IFNAME=%s", params.ifname.c_str()));
434}
435template <auto level, typename... Args>
436auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
437{
438 if (params)
439 {
440 return logWithChannel<level>(*params, std::forward<Args>(args)...);
441 }
442 return log<level>(std::forward<Args>(args)...);
443}
444
445/** @brief Trivializes using parameter getter functions by providing a bus
446 * and channel parameters automatically.
447 *
448 * @param[in] channel - The channel id corresponding to an ethernet interface
449 * ...
450 */
451template <auto func, typename... Args>
452auto channelCall(uint8_t channel, Args&&... args)
453{
454 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
455 auto params = getChannelParams(bus, channel);
456 return std::invoke(func, bus, params, std::forward<Args>(args)...);
457}
458
459/** @brief Determines if the ethernet interface is using DHCP
460 *
461 * @param[in] bus - The bus object used for lookups
462 * @param[in] params - The parameters for the channel
Johnathan Mantey65265362019-11-14 11:24:19 -0800463 * @return DHCPConf enumeration
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700464 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800465EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus::bus& bus,
466 const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700467{
Johnathan Mantey65265362019-11-14 11:24:19 -0800468 std::string dhcpstr = std::get<std::string>(getDbusProperty(
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700469 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
Johnathan Mantey65265362019-11-14 11:24:19 -0800470 return EthernetInterface::convertDHCPConfFromString(dhcpstr);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700471}
472
Johnathan Mantey65265362019-11-14 11:24:19 -0800473/** @brief Sets the DHCP v4 state on the given interface
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700474 *
Johnathan Mantey65265362019-11-14 11:24:19 -0800475 * @param[in] bus - The bus object used for lookups
476 * @param[in] params - The parameters for the channel
477 * @param[in] requestedDhcp - DHCP state to assign
478 * (EthernetInterface::DHCPConf::none,
479 * EthernetInterface::DHCPConf::v4,
480 * EthernetInterface::DHCPConf::v6,
481 * EthernetInterface::DHCPConf::both)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700482 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800483void setDHCPv4Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
484 const EthernetInterface::DHCPConf requestedDhcp)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700485{
Johnathan Mantey65265362019-11-14 11:24:19 -0800486 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
487 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
488
489 if ((currentDhcp == EthernetInterface::DHCPConf::v6) &&
490 (requestedDhcp == EthernetInterface::DHCPConf::v4))
491 {
492 nextDhcp = EthernetInterface::DHCPConf::both;
493 }
494 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
495 (requestedDhcp == EthernetInterface::DHCPConf::v4))
496
497 {
498 nextDhcp = requestedDhcp;
499 }
500 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
501 {
502 if (currentDhcp == EthernetInterface::DHCPConf::both)
503 {
504 nextDhcp = EthernetInterface::DHCPConf::v6;
505 }
506 else if (currentDhcp == EthernetInterface::DHCPConf::v4)
507 {
508 nextDhcp = EthernetInterface::DHCPConf::none;
509 }
510 }
511 else
512 {
513 nextDhcp = currentDhcp;
514 }
515 std::string newDhcp =
516 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
517 nextDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700518 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800519 "DHCPEnabled", newDhcp);
520}
521
522/** @brief Sets the DHCP v6 state on the given interface
523 *
524 * @param[in] bus - The bus object used for lookups
525 * @param[in] params - The parameters for the channel
526 * @param[in] requestedDhcp - DHCP state to assign (none, v6, both)
527 * @param[in] defaultMode - True: Use algorithmic assignment
528 * False: requestedDhcp assigned unconditionally
529 */
530void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
531 const EthernetInterface::DHCPConf requestedDhcp,
532 const bool defaultMode = true)
533{
534 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
535 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
536
537 if (defaultMode)
538 {
539 if ((currentDhcp == EthernetInterface::DHCPConf::v4) &&
540 (requestedDhcp == EthernetInterface::DHCPConf::v6))
541 {
542 nextDhcp = EthernetInterface::DHCPConf::both;
543 }
544 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
545 (requestedDhcp == EthernetInterface::DHCPConf::v6))
546
547 {
548 nextDhcp = requestedDhcp;
549 }
550 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
551 {
552 if (currentDhcp == EthernetInterface::DHCPConf::both)
553 {
554 nextDhcp = EthernetInterface::DHCPConf::v4;
555 }
556 else if (currentDhcp == EthernetInterface::DHCPConf::v6)
557 {
558 nextDhcp = EthernetInterface::DHCPConf::none;
559 }
560 }
561 else
562 {
563 nextDhcp = currentDhcp;
564 }
565 }
566 else
567 {
568 // allow the v6 call to set any value
569 nextDhcp = requestedDhcp;
570 }
571
572 std::string newDhcp =
573 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
574 nextDhcp);
575 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
576 "DHCPEnabled", newDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700577}
578
579/** @brief Converts a human readable MAC string into MAC bytes
580 *
581 * @param[in] mac - The MAC string
582 * @return MAC in bytes
583 */
584ether_addr stringToMAC(const char* mac)
585{
586 const ether_addr* ret = ether_aton(mac);
587 if (ret == nullptr)
588 {
589 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
590 elog<InternalFailure>();
591 }
592 return *ret;
593}
594
595/** @brief Determines the MAC of the ethernet interface
596 *
597 * @param[in] bus - The bus object used for lookups
598 * @param[in] params - The parameters for the channel
599 * @return The configured mac address
600 */
601ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
602{
603 auto macStr = std::get<std::string>(getDbusProperty(
604 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
605 return stringToMAC(macStr.c_str());
606}
607
608/** @brief Sets the system value for MAC address on the given interface
609 *
610 * @param[in] bus - The bus object used for lookups
611 * @param[in] params - The parameters for the channel
612 * @param[in] mac - MAC address to apply
613 */
614void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
615 const ether_addr& mac)
616{
617 std::string macStr = ether_ntoa(&mac);
618 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
619 macStr);
620}
621
622/** @brief Turns an IP address string into the network byte order form
623 * NOTE: This version strictly validates family matches
624 *
625 * @param[in] address - The string form of the address
626 * @return A network byte order address or none if conversion failed
627 */
628template <int family>
629std::optional<typename AddrFamily<family>::addr>
630 maybeStringToAddr(const char* address)
631{
632 typename AddrFamily<family>::addr ret;
633 if (inet_pton(family, address, &ret) == 1)
634 {
635 return ret;
636 }
637 return std::nullopt;
638}
639
640/** @brief Turns an IP address string into the network byte order form
641 * NOTE: This version strictly validates family matches
642 *
643 * @param[in] address - The string form of the address
644 * @return A network byte order address
645 */
646template <int family>
647typename AddrFamily<family>::addr stringToAddr(const char* address)
648{
649 auto ret = maybeStringToAddr<family>(address);
650 if (!ret)
651 {
652 log<level::ERR>("Failed to convert IP Address",
653 entry("FAMILY=%d", family),
654 entry("ADDRESS=%s", address));
655 elog<InternalFailure>();
656 }
657 return *ret;
658}
659
660/** @brief Turns an IP address in network byte order into a string
661 *
662 * @param[in] address - The string form of the address
663 * @return A network byte order address
664 */
665template <int family>
666std::string addrToString(const typename AddrFamily<family>::addr& address)
667{
668 std::string ret(AddrFamily<family>::maxStrLen, '\0');
669 inet_ntop(family, &address, ret.data(), ret.size());
670 ret.resize(strlen(ret.c_str()));
671 return ret;
672}
673
674/** @brief Retrieves the current gateway for the address family on the system
675 * NOTE: The gateway is currently system wide and not per channel
676 *
677 * @param[in] bus - The bus object used for lookups
678 * @param[in] params - The parameters for the channel
679 * @return An address representing the gateway address if it exists
680 */
681template <int family>
682std::optional<typename AddrFamily<family>::addr>
683 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
684{
685 auto gatewayStr = std::get<std::string>(getDbusProperty(
686 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
687 AddrFamily<family>::propertyGateway));
688 if (gatewayStr.empty())
689 {
690 return std::nullopt;
691 }
692 return stringToAddr<family>(gatewayStr.c_str());
693}
694
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700695/** @brief A lazy lookup mechanism for iterating over object properties stored
696 * in DBus. This will only perform the object lookup when needed, and
697 * retains a cache of previous lookups to speed up future iterations.
698 */
699class ObjectLookupCache
700{
701 public:
702 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
703
704 /** @brief Creates a new ObjectLookupCache for the interface on the bus
705 * NOTE: The inputs to this object must outlive the object since
706 * they are only referenced by it.
707 *
708 * @param[in] bus - The bus object used for lookups
709 * @param[in] params - The parameters for the channel
710 * @param[in] intf - The interface we are looking up
711 */
712 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
713 const char* intf) :
714 bus(bus),
715 params(params), intf(intf),
716 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
717 {
718 }
719
720 class iterator : public ObjectTree::const_iterator
721 {
722 public:
723 using value_type = PropertiesCache::value_type;
724
725 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
726 ObjectTree::const_iterator(it), container(container),
727 ret(container.cache.end())
728 {
729 }
730 value_type& operator*()
731 {
732 ret = container.get(ObjectTree::const_iterator::operator*().first);
733 return *ret;
734 }
735 value_type* operator->()
736 {
737 return &operator*();
738 }
739
740 private:
741 ObjectLookupCache& container;
742 PropertiesCache::iterator ret;
743 };
744
745 iterator begin() noexcept
746 {
747 return iterator(objs.begin(), *this);
748 }
749
750 iterator end() noexcept
751 {
752 return iterator(objs.end(), *this);
753 }
754
755 private:
756 sdbusplus::bus::bus& bus;
757 const ChannelParams& params;
758 const char* const intf;
759 const ObjectTree objs;
760 PropertiesCache cache;
761
762 /** @brief Gets a cached copy of the object properties if possible
763 * Otherwise performs a query on DBus to look them up
764 *
765 * @param[in] path - The object path to lookup
766 * @return An iterator for the specified object path + properties
767 */
768 PropertiesCache::iterator get(const std::string& path)
769 {
770 auto it = cache.find(path);
771 if (it != cache.end())
772 {
773 return it;
774 }
775 auto properties = getAllDbusProperties(bus, params.service, path, intf);
776 return cache.insert({path, std::move(properties)}).first;
777 }
778};
779
780/** @brief Searches the ip object lookup cache for an address matching
781 * the input parameters. NOTE: The index lacks stability across address
782 * changes since the network daemon has no notion of stable indicies.
783 *
784 * @param[in] bus - The bus object used for lookups
785 * @param[in] params - The parameters for the channel
786 * @param[in] idx - The index of the desired address on the interface
787 * @param[in] origins - The allowed origins for the address objects
788 * @param[in] ips - The object lookup cache holding all of the address info
789 * @return The address and prefix if it was found
790 */
791template <int family>
792std::optional<IfAddr<family>>
793 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
794 uint8_t idx,
795 const std::unordered_set<IP::AddressOrigin>& origins,
796 ObjectLookupCache& ips)
797{
798 for (const auto& [path, properties] : ips)
799 {
800 const auto& addrStr = std::get<std::string>(properties.at("Address"));
801 auto addr = maybeStringToAddr<family>(addrStr.c_str());
802 if (!addr)
803 {
804 continue;
805 }
806
807 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
808 std::get<std::string>(properties.at("Origin")));
809 if (origins.find(origin) == origins.end())
810 {
811 continue;
812 }
813
814 if (idx > 0)
815 {
816 idx--;
817 continue;
818 }
819
820 IfAddr<family> ifaddr;
821 ifaddr.path = path;
822 ifaddr.address = *addr;
823 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
824 ifaddr.origin = origin;
825 return std::move(ifaddr);
826 }
827
828 return std::nullopt;
829}
830
831/** @brief Trivial helper around findIfAddr that simplifies calls
832 * for one off lookups. Don't use this if you intend to do multiple
833 * lookups at a time.
834 *
835 * @param[in] bus - The bus object used for lookups
836 * @param[in] params - The parameters for the channel
837 * @param[in] idx - The index of the desired address on the interface
838 * @param[in] origins - The allowed origins for the address objects
839 * @return The address and prefix if it was found
840 */
841template <int family>
842auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
843 uint8_t idx,
844 const std::unordered_set<IP::AddressOrigin>& origins)
845{
846 ObjectLookupCache ips(bus, params, INTF_IP);
847 return findIfAddr<family>(bus, params, idx, origins, ips);
848}
849
850/** @brief Deletes the dbus object. Ignores empty objects or objects that are
851 * missing from the bus.
852 *
853 * @param[in] bus - The bus object used for lookups
854 * @param[in] service - The name of the service
855 * @param[in] path - The path of the object to delete
856 */
857void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
858 const std::string& path)
859{
860 if (path.empty())
861 {
862 return;
863 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530864 try
tomjose26e17732016-03-03 08:52:51 -0600865 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700866 auto req = bus.new_method_call(service.c_str(), path.c_str(),
867 ipmi::DELETE_INTERFACE, "Delete");
868 bus.call_noreply(req);
869 }
870 catch (const sdbusplus::exception::SdBusError& e)
871 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000872 if (strcmp(e.name(),
873 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
874 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600875 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700876 // We want to rethrow real errors
877 throw;
tomjose26e17732016-03-03 08:52:51 -0600878 }
879 }
tomjose26e17732016-03-03 08:52:51 -0600880}
881
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700882/** @brief Sets the address info configured for the interface
883 * If a previous address path exists then it will be removed
884 * before the new address is added.
885 *
886 * @param[in] bus - The bus object used for lookups
887 * @param[in] params - The parameters for the channel
888 * @param[in] address - The address of the new IP
889 * @param[in] prefix - The prefix of the new IP
890 */
891template <int family>
892void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
893 const typename AddrFamily<family>::addr& address,
894 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530895{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700896 auto newreq =
897 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
898 INTF_IP_CREATE, "IP");
899 std::string protocol =
900 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
901 AddrFamily<family>::protocol);
902 newreq.append(protocol, addrToString<family>(address), prefix, "");
903 bus.call_noreply(newreq);
904}
Tom Josepha30c8d32018-03-22 02:15:03 +0530905
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700906/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
907 *
908 * @param[in] bus - The bus object used for lookups
909 * @param[in] params - The parameters for the channel
910 * @return The address and prefix if found
911 */
912auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530913{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700914 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
915}
Tom Josepha30c8d32018-03-22 02:15:03 +0530916
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700917/** @brief Reconfigures the IPv4 address info configured for the interface
918 *
919 * @param[in] bus - The bus object used for lookups
920 * @param[in] params - The parameters for the channel
921 * @param[in] address - The new address if specified
922 * @param[in] prefix - The new address prefix if specified
923 */
924void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
925 const std::optional<in_addr>& address,
926 std::optional<uint8_t> prefix)
927{
928 auto ifaddr = getIfAddr4(bus, params);
929 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530930 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700931 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530932 elog<InternalFailure>();
933 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700934 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
935 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530936 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700937 fallbackPrefix = ifaddr->prefix;
938 deleteObjectIfExists(bus, params.service, ifaddr->path);
939 }
940 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
941 prefix.value_or(fallbackPrefix));
942}
943
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700944template <int family>
945std::optional<IfNeigh<family>>
946 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
947 const typename AddrFamily<family>::addr& ip,
948 ObjectLookupCache& neighbors)
949{
950 const auto state =
951 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
952 Neighbor::State::Permanent);
953 for (const auto& [path, neighbor] : neighbors)
954 {
955 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
956 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
957 if (!neighIP)
958 {
959 continue;
960 }
961 if (!equal(*neighIP, ip))
962 {
963 continue;
964 }
965 if (state != std::get<std::string>(neighbor.at("State")))
966 {
967 continue;
968 }
969
970 IfNeigh<family> ret;
971 ret.path = path;
972 ret.ip = ip;
973 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
974 ret.mac = stringToMAC(macStr.c_str());
975 return std::move(ret);
976 }
977
978 return std::nullopt;
979}
980
981template <int family>
982void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
983 const typename AddrFamily<family>::addr& address,
984 const ether_addr& mac)
985{
986 auto newreq =
987 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
988 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
989 std::string macStr = ether_ntoa(&mac);
990 newreq.append(addrToString<family>(address), macStr);
991 bus.call_noreply(newreq);
992}
993
994/** @brief Sets the system wide value for the default gateway
995 *
996 * @param[in] bus - The bus object used for lookups
997 * @param[in] params - The parameters for the channel
998 * @param[in] gateway - Gateway address to apply
999 */
1000template <int family>
1001void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
1002 const typename AddrFamily<family>::addr& address)
1003{
1004 // Save the old gateway MAC address if it exists so we can recreate it
1005 auto gateway = getGatewayProperty<family>(bus, params);
1006 std::optional<IfNeigh<family>> neighbor;
1007 if (gateway)
1008 {
1009 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1010 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
1011 }
1012
1013 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
1014 AddrFamily<family>::propertyGateway,
1015 addrToString<family>(address));
1016
1017 // Restore the gateway MAC if we had one
1018 if (neighbor)
1019 {
1020 deleteObjectIfExists(bus, params.service, neighbor->path);
1021 createNeighbor<family>(bus, params, address, neighbor->mac);
1022 }
1023}
1024
1025template <int family>
1026std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
1027 const ChannelParams& params,
1028 ObjectLookupCache& neighbors)
1029{
1030 auto gateway = getGatewayProperty<family>(bus, params);
1031 if (!gateway)
1032 {
1033 return std::nullopt;
1034 }
1035
1036 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
1037}
1038
1039template <int family>
1040std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
1041 const ChannelParams& params)
1042{
1043 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1044 return findGatewayNeighbor<family>(bus, params, neighbors);
1045}
1046
1047template <int family>
1048void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
1049 const ChannelParams& params, const ether_addr& mac)
1050{
1051 auto gateway = getGatewayProperty<family>(bus, params);
1052 if (!gateway)
1053 {
1054 log<level::ERR>("Tried to set Gateway MAC without Gateway");
1055 elog<InternalFailure>();
1056 }
1057
1058 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1059 auto neighbor =
1060 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
1061 if (neighbor)
1062 {
1063 deleteObjectIfExists(bus, params.service, neighbor->path);
1064 }
1065
1066 createNeighbor<family>(bus, params, *gateway, mac);
1067}
1068
William A. Kennington III16064aa2019-04-13 17:44:53 -07001069/** @brief Deconfigures the IPv6 address info configured for the interface
1070 *
1071 * @param[in] bus - The bus object used for lookups
1072 * @param[in] params - The parameters for the channel
1073 * @param[in] idx - The address index to operate on
1074 */
1075void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
1076 uint8_t idx)
1077{
1078 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
1079 if (ifaddr)
1080 {
1081 deleteObjectIfExists(bus, params.service, ifaddr->path);
1082 }
1083}
1084
1085/** @brief Reconfigures the IPv6 address info configured for the interface
1086 *
1087 * @param[in] bus - The bus object used for lookups
1088 * @param[in] params - The parameters for the channel
1089 * @param[in] idx - The address index to operate on
1090 * @param[in] address - The new address
1091 * @param[in] prefix - The new address prefix
1092 */
1093void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
1094 uint8_t idx, const in6_addr& address, uint8_t prefix)
1095{
1096 deconfigureIfAddr6(bus, params, idx);
1097 createIfAddr<AF_INET6>(bus, params, address, prefix);
1098}
1099
1100/** @brief Converts the AddressOrigin into an IPv6Source
1101 *
1102 * @param[in] origin - The DBus Address Origin to convert
1103 * @return The IPv6Source version of the origin
1104 */
1105IPv6Source originToSourceType(IP::AddressOrigin origin)
1106{
1107 switch (origin)
1108 {
1109 case IP::AddressOrigin::Static:
1110 return IPv6Source::Static;
1111 case IP::AddressOrigin::DHCP:
1112 return IPv6Source::DHCP;
1113 case IP::AddressOrigin::SLAAC:
1114 return IPv6Source::SLAAC;
1115 default:
1116 {
1117 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
1118 convertForMessage(origin);
1119 log<level::ERR>(
1120 "Invalid IP::AddressOrigin conversion to IPv6Source",
1121 entry("ORIGIN=%s", originStr.c_str()));
1122 elog<InternalFailure>();
1123 }
1124 }
1125}
1126
1127/** @brief Packs the IPMI message response with IPv6 address data
1128 *
1129 * @param[out] ret - The IPMI response payload to be packed
1130 * @param[in] channel - The channel id corresponding to an ethernet interface
1131 * @param[in] set - The set selector for determining address index
1132 * @param[in] origins - Set of valid origins for address filtering
1133 */
1134void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
1135 const std::unordered_set<IP::AddressOrigin>& origins)
1136{
1137 auto source = IPv6Source::Static;
1138 bool enabled = false;
1139 in6_addr addr{};
1140 uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
1141 auto status = IPv6AddressStatus::Disabled;
1142
1143 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
1144 if (ifaddr)
1145 {
1146 source = originToSourceType(ifaddr->origin);
1147 enabled = true;
1148 addr = ifaddr->address;
1149 prefix = ifaddr->prefix;
1150 status = IPv6AddressStatus::Active;
1151 }
1152
1153 ret.pack(set);
1154 ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled);
1155 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
1156 ret.pack(prefix);
1157 ret.pack(static_cast<uint8_t>(status));
1158}
1159
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001160/** @brief Gets the vlan ID configured on the interface
1161 *
1162 * @param[in] bus - The bus object used for lookups
1163 * @param[in] params - The parameters for the channel
1164 * @return VLAN id or the standard 0 for no VLAN
1165 */
1166uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
1167{
1168 // VLAN devices will always have a separate logical object
1169 if (params.ifPath == params.logicalPath)
1170 {
1171 return 0;
1172 }
1173
1174 auto vlan = std::get<uint32_t>(getDbusProperty(
1175 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
1176 if ((vlan & VLAN_VALUE_MASK) != vlan)
1177 {
1178 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
1179 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +05301180 elog<InternalFailure>();
1181 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001182 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +05301183}
1184
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001185/** @brief Deletes all of the possible configuration parameters for a channel
1186 *
1187 * @param[in] bus - The bus object used for lookups
1188 * @param[in] params - The parameters for the channel
1189 */
1190void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001191{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001192 // Delete all objects associated with the interface
1193 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
1194 "GetSubTree");
1195 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
1196 auto objreply = bus.call(objreq);
1197 ObjectTree objs;
1198 objreply.read(objs);
1199 for (const auto& [path, impls] : objs)
1200 {
1201 if (path.find(params.ifname) == path.npos)
1202 {
1203 continue;
1204 }
1205 for (const auto& [service, intfs] : impls)
1206 {
1207 deleteObjectIfExists(bus, service, path);
1208 }
1209 // Update params to reflect the deletion of vlan
1210 if (path == params.logicalPath)
1211 {
1212 params.logicalPath = params.ifPath;
1213 }
1214 }
1215
1216 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -08001217 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001218}
1219
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001220/** @brief Creates a new VLAN on the specified interface
1221 *
1222 * @param[in] bus - The bus object used for lookups
1223 * @param[in] params - The parameters for the channel
1224 * @param[in] vlan - The id of the new vlan
1225 */
1226void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +05301227{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001228 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301229 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001230 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301231 }
1232
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001233 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
1234 INTF_VLAN_CREATE, "VLAN");
1235 req.append(params.ifname, static_cast<uint32_t>(vlan));
1236 auto reply = bus.call(req);
1237 sdbusplus::message::object_path newPath;
1238 reply.read(newPath);
1239 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +05301240}
1241
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001242/** @brief Performs the necessary reconfiguration to change the VLAN
1243 *
1244 * @param[in] bus - The bus object used for lookups
1245 * @param[in] params - The parameters for the channel
1246 * @param[in] vlan - The new vlan id to use
1247 */
1248void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
1249 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001250{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001251 // Unfortunatetly we don't have built-in functions to migrate our interface
1252 // customizations to new VLAN interfaces, or have some kind of decoupling.
1253 // We therefore must retain all of our old information, setup the new VLAN
1254 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +08001255
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001256 // Save info from the old logical interface
1257 ObjectLookupCache ips(bus, params, INTF_IP);
1258 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001259 std::vector<IfAddr<AF_INET6>> ifaddrs6;
1260 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
1261 {
1262 auto ifaddr6 =
1263 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
1264 if (!ifaddr6)
1265 {
1266 break;
1267 }
1268 ifaddrs6.push_back(std::move(*ifaddr6));
1269 }
Johnathan Mantey65265362019-11-14 11:24:19 -08001270 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001271 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
1272 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001273 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001274
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001275 deconfigureChannel(bus, params);
1276 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001277
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001278 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -08001279 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001280 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001281 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001282 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001283 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001284 for (const auto& ifaddr6 : ifaddrs6)
1285 {
1286 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
1287 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001288 if (neighbor4)
1289 {
1290 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
1291 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001292 if (neighbor6)
1293 {
1294 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
1295 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001296}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001297
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001298/** @brief Turns a prefix into a netmask
1299 *
1300 * @param[in] prefix - The prefix length
1301 * @return The netmask
1302 */
1303in_addr prefixToNetmask(uint8_t prefix)
1304{
1305 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001306 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001307 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
1308 elog<InternalFailure>();
1309 }
1310 if (prefix == 0)
1311 {
1312 // Avoids 32-bit lshift by 32 UB
1313 return {};
1314 }
1315 return {htobe32(~UINT32_C(0) << (32 - prefix))};
1316}
1317
1318/** @brief Turns a a netmask into a prefix length
1319 *
1320 * @param[in] netmask - The netmask in byte form
1321 * @return The prefix length
1322 */
1323uint8_t netmaskToPrefix(in_addr netmask)
1324{
1325 uint32_t x = be32toh(netmask.s_addr);
1326 if ((~x & (~x + 1)) != 0)
1327 {
1328 char maskStr[INET_ADDRSTRLEN];
1329 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
1330 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
1331 elog<InternalFailure>();
1332 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -08001333 return static_cast<bool>(x)
1334 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
1335 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001336}
1337
1338// We need to store this value so it can be returned to the client
1339// It is volatile so safe to store in daemon memory.
1340static std::unordered_map<uint8_t, SetStatus> setStatus;
1341
1342// Until we have good support for fixed versions of IPMI tool
1343// we need to return the VLAN id for disabled VLANs. The value is only
1344// used for verification that a disable operation succeeded and will only
1345// be sent if our system indicates that vlans are disabled.
1346static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
1347
1348/** @brief Gets the set status for the channel if it exists
1349 * Otherise populates and returns the default value.
1350 *
1351 * @param[in] channel - The channel id corresponding to an ethernet interface
1352 * @return A reference to the SetStatus for the channel
1353 */
1354SetStatus& getSetStatus(uint8_t channel)
1355{
1356 auto it = setStatus.find(channel);
1357 if (it != setStatus.end())
1358 {
1359 return it->second;
1360 }
1361 return setStatus[channel] = SetStatus::Complete;
1362}
1363
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001364/**
1365 * Define placeholder command handlers for the OEM Extension bytes for the Set
1366 * LAN Configuration Parameters and Get LAN Configuration Parameters
1367 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
1368 * functions below to be overridden.
1369 * To create handlers for your own proprietary command set:
1370 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
1371 * recipe
1372 * Create C++ file(s) that define IPMI handler functions matching the
1373 * function names below (i.e. setLanOem). The default name for the
1374 * transport IPMI commands is transporthandler_oem.cpp.
1375 * Add:
1376 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
1377 * Create a do_compile_prepend()/do_install_append method in your
1378 * bbappend file to copy the file to the build directory.
1379 * Add:
1380 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
1381 * # Copy the "strong" functions into the working directory, overriding the
1382 * # placeholder functions.
1383 * do_compile_prepend(){
1384 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
1385 * }
1386 *
1387 * # Clean up after complilation has completed
1388 * do_install_append(){
1389 * rm -f ${S}/transporthandler_oem.cpp
1390 * }
1391 *
1392 */
1393
1394/**
1395 * Define the placeholder OEM commands as having weak linkage. Create
1396 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
1397 * file. The functions defined there must not have the "weak" attribute
1398 * applied to them.
1399 */
1400RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1401 __attribute__((weak));
1402RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1403 uint8_t set, uint8_t block)
1404 __attribute__((weak));
1405
1406RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
1407{
1408 req.trailingOk = true;
1409 return response(ccParamNotSupported);
1410}
1411
1412RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
1413 uint8_t set, uint8_t block)
1414{
1415 return response(ccParamNotSupported);
1416}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301417/**
1418 * @brief is MAC address valid.
1419 *
1420 * This function checks whether the MAC address is valid or not.
1421 *
1422 * @param[in] mac - MAC address.
1423 * @return true if MAC address is valid else retun false.
1424 **/
1425bool isValidMACAddress(const ether_addr& mac)
1426{
1427 // check if mac address is empty
1428 if (equal(mac, ether_addr{}))
1429 {
1430 return false;
1431 }
1432 // we accept only unicast MAC addresses and same thing has been checked in
1433 // phosphor-network layer. If the least significant bit of the first octet
1434 // is set to 1, it is multicast MAC else it is unicast MAC address.
1435 if (mac.ether_addr_octet[0] & 1)
1436 {
1437 return false;
1438 }
1439 return true;
1440}
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001441
vijayabharathix shettycc769252020-02-27 17:52:20 +00001442RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1443 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001444{
vijayabharathix shettycc769252020-02-27 17:52:20 +00001445 const uint8_t channel = convertCurrentChannelNum(
1446 static_cast<uint8_t>(channelBits), ctx->channel);
1447 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001448 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001449 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001450 req.trailingOk = true;
1451 return responseInvalidFieldRequest();
1452 }
1453
1454 switch (static_cast<LanParam>(parameter))
1455 {
1456 case LanParam::SetStatus:
1457 {
1458 uint2_t flag;
1459 uint6_t rsvd;
1460 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1461 {
1462 return responseReqDataLenInvalid();
1463 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001464 if (rsvd)
1465 {
1466 return responseInvalidFieldRequest();
1467 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001468 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1469 switch (status)
1470 {
1471 case SetStatus::Complete:
1472 {
1473 getSetStatus(channel) = status;
1474 return responseSuccess();
1475 }
1476 case SetStatus::InProgress:
1477 {
1478 auto& storedStatus = getSetStatus(channel);
1479 if (storedStatus == SetStatus::InProgress)
1480 {
1481 return response(ccParamSetLocked);
1482 }
1483 storedStatus = status;
1484 return responseSuccess();
1485 }
1486 case SetStatus::Commit:
1487 if (getSetStatus(channel) != SetStatus::InProgress)
1488 {
1489 return responseInvalidFieldRequest();
1490 }
1491 return responseSuccess();
1492 }
1493 return response(ccParamNotSupported);
1494 }
1495 case LanParam::AuthSupport:
1496 {
1497 req.trailingOk = true;
1498 return response(ccParamReadOnly);
1499 }
1500 case LanParam::AuthEnables:
1501 {
1502 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -08001503 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001504 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001505 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001506 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001507 EthernetInterface::DHCPConf dhcp =
1508 channelCall<getDHCPProperty>(channel);
1509 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1510 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001511 {
1512 return responseCommandNotAvailable();
1513 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001514 in_addr ip;
1515 std::array<uint8_t, sizeof(ip)> bytes;
1516 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1517 {
1518 return responseReqDataLenInvalid();
1519 }
1520 copyInto(ip, bytes);
1521 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1522 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301523 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001524 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301525 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001526 uint4_t flag;
1527 uint4_t rsvd;
1528 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1529 {
1530 return responseReqDataLenInvalid();
1531 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001532 if (rsvd)
1533 {
1534 return responseInvalidFieldRequest();
1535 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001536 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1537 {
1538 case IPSrc::DHCP:
1539 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001540 // The IPSrc IPMI command is only for IPv4
1541 // management. Modifying IPv6 state is done using
1542 // a completely different Set LAN Configuration
1543 // subcommand.
1544 channelCall<setDHCPv4Property>(
1545 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001546 return responseSuccess();
1547 }
1548 case IPSrc::Unspecified:
1549 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001550 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001551 channelCall<setDHCPv4Property>(
1552 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001553 return responseSuccess();
1554 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +05301555 case IPSrc::BIOS:
1556 case IPSrc::BMC:
1557 {
1558 return responseInvalidFieldRequest();
1559 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001560 }
1561 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301562 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001563 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301564 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001565 ether_addr mac;
1566 std::array<uint8_t, sizeof(mac)> bytes;
1567 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301568 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001569 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301570 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001571 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301572
1573 if (!isValidMACAddress(mac))
1574 {
1575 return responseInvalidFieldRequest();
1576 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001577 channelCall<setMACProperty>(channel, mac);
1578 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301579 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001580 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301581 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001582 EthernetInterface::DHCPConf dhcp =
1583 channelCall<getDHCPProperty>(channel);
1584 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1585 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001586 {
1587 return responseCommandNotAvailable();
1588 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001589 in_addr netmask;
1590 std::array<uint8_t, sizeof(netmask)> bytes;
1591 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301592 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001593 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301594 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001595 copyInto(netmask, bytes);
1596 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1597 netmaskToPrefix(netmask));
1598 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301599 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001600 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301601 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001602 EthernetInterface::DHCPConf dhcp =
1603 channelCall<getDHCPProperty>(channel);
1604 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1605 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001606 {
1607 return responseCommandNotAvailable();
1608 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001609 in_addr gateway;
1610 std::array<uint8_t, sizeof(gateway)> bytes;
1611 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1612 {
1613 return responseReqDataLenInvalid();
1614 }
1615 copyInto(gateway, bytes);
1616 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1617 return responseSuccess();
1618 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001619 case LanParam::Gateway1MAC:
1620 {
1621 ether_addr gatewayMAC;
1622 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1623 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1624 {
1625 return responseReqDataLenInvalid();
1626 }
1627 copyInto(gatewayMAC, bytes);
1628 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1629 return responseSuccess();
1630 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001631 case LanParam::VLANId:
1632 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301633 uint12_t vlanData = 0;
1634 uint3_t reserved = 0;
1635 bool vlanEnable = 0;
1636
1637 if (req.unpack(vlanData) || req.unpack(reserved) ||
1638 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001639 {
1640 return responseReqDataLenInvalid();
1641 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301642
1643 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001644 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301645 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001646 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301647
1648 uint16_t vlan = static_cast<uint16_t>(vlanData);
1649
1650 if (!vlanEnable)
1651 {
1652 lastDisabledVlan[channel] = vlan;
1653 vlan = 0;
1654 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001655 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1656 {
1657 return responseInvalidFieldRequest();
1658 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301659
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001660 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001661 return responseSuccess();
1662 }
1663 case LanParam::CiphersuiteSupport:
1664 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001665 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001666 {
1667 req.trailingOk = true;
1668 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301669 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001670 case LanParam::IPFamilyEnables:
1671 {
1672 uint8_t enables;
1673 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1674 {
1675 return responseReqDataLenInvalid();
1676 }
1677 switch (static_cast<IPFamilyEnables>(enables))
1678 {
1679 case IPFamilyEnables::DualStack:
1680 return responseSuccess();
1681 case IPFamilyEnables::IPv4Only:
1682 case IPFamilyEnables::IPv6Only:
1683 return response(ccParamNotSupported);
1684 }
1685 return response(ccParamNotSupported);
1686 }
1687 case LanParam::IPv6Status:
1688 {
1689 req.trailingOk = true;
1690 return response(ccParamReadOnly);
1691 }
1692 case LanParam::IPv6StaticAddresses:
1693 {
1694 uint8_t set;
1695 uint7_t rsvd;
1696 bool enabled;
1697 in6_addr ip;
1698 std::array<uint8_t, sizeof(ip)> ipbytes;
1699 uint8_t prefix;
1700 uint8_t status;
1701 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1702 !req.fullyUnpacked())
1703 {
1704 return responseReqDataLenInvalid();
1705 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001706 if (rsvd)
1707 {
1708 return responseInvalidFieldRequest();
1709 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001710 copyInto(ip, ipbytes);
1711 if (enabled)
1712 {
1713 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1714 }
1715 else
1716 {
1717 channelCall<deconfigureIfAddr6>(channel, set);
1718 }
1719 return responseSuccess();
1720 }
1721 case LanParam::IPv6DynamicAddresses:
1722 {
1723 req.trailingOk = true;
1724 return response(ccParamReadOnly);
1725 }
1726 case LanParam::IPv6RouterControl:
1727 {
1728 std::bitset<8> control;
1729 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1730 {
1731 return responseReqDataLenInvalid();
1732 }
1733 std::bitset<8> expected;
Johnathan Mantey65265362019-11-14 11:24:19 -08001734 EthernetInterface::DHCPConf dhcp =
1735 channelCall<getDHCPProperty>(channel);
1736 if ((dhcp == EthernetInterface::DHCPConf::both) |
1737 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001738 {
1739 expected[IPv6RouterControlFlag::Dynamic] = 1;
1740 }
1741 else
1742 {
1743 expected[IPv6RouterControlFlag::Static] = 1;
1744 }
1745 if (expected != control)
1746 {
1747 return responseInvalidFieldRequest();
1748 }
1749 return responseSuccess();
1750 }
1751 case LanParam::IPv6StaticRouter1IP:
1752 {
1753 in6_addr gateway;
1754 std::array<uint8_t, sizeof(gateway)> bytes;
1755 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1756 {
1757 return responseReqDataLenInvalid();
1758 }
1759 copyInto(gateway, bytes);
1760 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1761 return responseSuccess();
1762 }
1763 case LanParam::IPv6StaticRouter1MAC:
1764 {
1765 ether_addr mac;
1766 std::array<uint8_t, sizeof(mac)> bytes;
1767 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1768 {
1769 return responseReqDataLenInvalid();
1770 }
1771 copyInto(mac, bytes);
1772 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1773 return responseSuccess();
1774 }
1775 case LanParam::IPv6StaticRouter1PrefixLength:
1776 {
1777 uint8_t prefix;
1778 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1779 {
1780 return responseReqDataLenInvalid();
1781 }
1782 if (prefix != 0)
1783 {
1784 return responseInvalidFieldRequest();
1785 }
1786 return responseSuccess();
1787 }
1788 case LanParam::IPv6StaticRouter1PrefixValue:
1789 {
1790 std::array<uint8_t, sizeof(in6_addr)> bytes;
1791 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1792 {
1793 return responseReqDataLenInvalid();
1794 }
1795 // Accept any prefix value since our prefix length has to be 0
1796 return responseSuccess();
1797 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001798 case LanParam::cipherSuitePrivilegeLevels:
1799 {
1800 uint8_t reserved;
1801 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1802
1803 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1804 {
1805 return responseReqDataLenInvalid();
1806 }
1807
1808 if (reserved)
1809 {
1810 return responseInvalidFieldRequest();
1811 }
1812
1813 uint8_t resp =
1814 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1815 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1816 if (!resp)
1817 {
1818 return responseSuccess();
1819 }
1820 else
1821 {
1822 req.trailingOk = true;
1823 return response(resp);
1824 }
1825 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301826 }
vishwa1eaea4f2016-02-26 11:57:40 -06001827
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001828 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1829 {
1830 return setLanOem(channel, parameter, req);
1831 }
1832
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001833 req.trailingOk = true;
1834 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001835}
1836
vijayabharathix shettycc769252020-02-27 17:52:20 +00001837RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1838 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001839 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301840{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001841 message::Payload ret;
1842 constexpr uint8_t current_revision = 0x11;
1843 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001844
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001845 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301846 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001847 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301848 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001849
vijayabharathix shettycc769252020-02-27 17:52:20 +00001850 const uint8_t channel = convertCurrentChannelNum(
1851 static_cast<uint8_t>(channelBits), ctx->channel);
1852 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001853 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001854 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001855 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001856 }
1857
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001858 static std::vector<uint8_t> cipherList;
1859 static bool listInit = false;
1860 if (!listInit)
1861 {
1862 try
1863 {
1864 cipherList = cipher::getCipherList();
1865 listInit = true;
1866 }
1867 catch (const std::exception& e)
1868 {
1869 }
1870 }
1871
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001872 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301873 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001874 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301875 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001876 SetStatus status;
1877 try
1878 {
1879 status = setStatus.at(channel);
1880 }
1881 catch (const std::out_of_range&)
1882 {
1883 status = SetStatus::Complete;
1884 }
1885 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1886 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301887 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001888 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301889 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001890 std::bitset<6> support;
1891 ret.pack(support, uint2_t{});
1892 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301893 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001894 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001895 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001896 std::bitset<6> enables;
1897 ret.pack(enables, uint2_t{}); // Callback
1898 ret.pack(enables, uint2_t{}); // User
1899 ret.pack(enables, uint2_t{}); // Operator
1900 ret.pack(enables, uint2_t{}); // Admin
1901 ret.pack(enables, uint2_t{}); // OEM
1902 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001903 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001904 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001905 {
1906 auto ifaddr = channelCall<getIfAddr4>(channel);
1907 in_addr addr{};
1908 if (ifaddr)
1909 {
1910 addr = ifaddr->address;
1911 }
1912 ret.pack(dataRef(addr));
1913 return responseSuccess(std::move(ret));
1914 }
1915 case LanParam::IPSrc:
1916 {
1917 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001918 EthernetInterface::DHCPConf dhcp =
1919 channelCall<getDHCPProperty>(channel);
1920 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1921 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001922 {
1923 src = IPSrc::DHCP;
1924 }
1925 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1926 return responseSuccess(std::move(ret));
1927 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001928 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001929 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001930 ether_addr mac = channelCall<getMACProperty>(channel);
1931 ret.pack(dataRef(mac));
1932 return responseSuccess(std::move(ret));
1933 }
1934 case LanParam::SubnetMask:
1935 {
1936 auto ifaddr = channelCall<getIfAddr4>(channel);
1937 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1938 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301939 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001940 prefix = ifaddr->prefix;
1941 }
1942 in_addr netmask = prefixToNetmask(prefix);
1943 ret.pack(dataRef(netmask));
1944 return responseSuccess(std::move(ret));
1945 }
1946 case LanParam::Gateway1:
1947 {
1948 auto gateway =
1949 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1950 in_addr{});
1951 ret.pack(dataRef(gateway));
1952 return responseSuccess(std::move(ret));
1953 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001954 case LanParam::Gateway1MAC:
1955 {
1956 ether_addr mac{};
1957 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1958 if (neighbor)
1959 {
1960 mac = neighbor->mac;
1961 }
1962 ret.pack(dataRef(mac));
1963 return responseSuccess(std::move(ret));
1964 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001965 case LanParam::VLANId:
1966 {
1967 uint16_t vlan = channelCall<getVLANProperty>(channel);
1968 if (vlan != 0)
1969 {
1970 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301971 }
1972 else
1973 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001974 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301975 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001976 ret.pack(vlan);
1977 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001978 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001979 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001980 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001981 if (getChannelSessionSupport(channel) ==
1982 EChannelSessSupported::none)
1983 {
1984 return responseInvalidFieldRequest();
1985 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001986 if (!listInit)
1987 {
1988 return responseUnspecifiedError();
1989 }
1990 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1991 return responseSuccess(std::move(ret));
1992 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001993 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001994 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001995 if (getChannelSessionSupport(channel) ==
1996 EChannelSessSupported::none)
1997 {
1998 return responseInvalidFieldRequest();
1999 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07002000 if (!listInit)
2001 {
2002 return responseUnspecifiedError();
2003 }
2004 ret.pack(cipherList);
2005 return responseSuccess(std::move(ret));
2006 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07002007 case LanParam::IPFamilySupport:
2008 {
2009 std::bitset<8> support;
2010 support[IPFamilySupportFlag::IPv6Only] = 0;
2011 support[IPFamilySupportFlag::DualStack] = 1;
2012 support[IPFamilySupportFlag::IPv6Alerts] = 1;
2013 ret.pack(support);
2014 return responseSuccess(std::move(ret));
2015 }
2016 case LanParam::IPFamilyEnables:
2017 {
2018 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
2019 return responseSuccess(std::move(ret));
2020 }
2021 case LanParam::IPv6Status:
2022 {
2023 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
2024 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
2025 std::bitset<8> support;
2026 support[IPv6StatusFlag::DHCP] = 1;
2027 support[IPv6StatusFlag::SLAAC] = 1;
2028 ret.pack(support);
2029 return responseSuccess(std::move(ret));
2030 }
2031 case LanParam::IPv6StaticAddresses:
2032 {
2033 if (set >= MAX_IPV6_STATIC_ADDRESSES)
2034 {
2035 return responseParmOutOfRange();
2036 }
2037 getLanIPv6Address(ret, channel, set, originsV6Static);
2038 return responseSuccess(std::move(ret));
2039 }
2040 case LanParam::IPv6DynamicAddresses:
2041 {
2042 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
2043 {
2044 return responseParmOutOfRange();
2045 }
2046 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
2047 return responseSuccess(std::move(ret));
2048 }
2049 case LanParam::IPv6RouterControl:
2050 {
2051 std::bitset<8> control;
Johnathan Mantey65265362019-11-14 11:24:19 -08002052 EthernetInterface::DHCPConf dhcp =
2053 channelCall<getDHCPProperty>(channel);
2054 if ((dhcp == EthernetInterface::DHCPConf::both) ||
2055 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07002056 {
2057 control[IPv6RouterControlFlag::Dynamic] = 1;
2058 }
2059 else
2060 {
2061 control[IPv6RouterControlFlag::Static] = 1;
2062 }
2063 ret.pack(control);
2064 return responseSuccess(std::move(ret));
2065 }
2066 case LanParam::IPv6StaticRouter1IP:
2067 {
2068 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08002069 EthernetInterface::DHCPConf dhcp =
2070 channelCall<getDHCPProperty>(channel);
2071 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
2072 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07002073 {
2074 gateway =
2075 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
2076 in6_addr{});
2077 }
2078 ret.pack(dataRef(gateway));
2079 return responseSuccess(std::move(ret));
2080 }
2081 case LanParam::IPv6StaticRouter1MAC:
2082 {
2083 ether_addr mac{};
2084 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
2085 if (neighbor)
2086 {
2087 mac = neighbor->mac;
2088 }
2089 ret.pack(dataRef(mac));
2090 return responseSuccess(std::move(ret));
2091 }
2092 case LanParam::IPv6StaticRouter1PrefixLength:
2093 {
2094 ret.pack(UINT8_C(0));
2095 return responseSuccess(std::move(ret));
2096 }
2097 case LanParam::IPv6StaticRouter1PrefixValue:
2098 {
2099 in6_addr prefix{};
2100 ret.pack(dataRef(prefix));
2101 return responseSuccess(std::move(ret));
2102 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00002103 case LanParam::cipherSuitePrivilegeLevels:
2104 {
2105 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
2106
2107 uint8_t resp =
2108 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
2109 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
2110 if (!resp)
2111 {
2112 constexpr uint8_t reserved1 = 0x00;
2113 ret.pack(reserved1, csPrivilegeLevels);
2114 return responseSuccess(std::move(ret));
2115 }
2116 else
2117 {
2118 return response(resp);
2119 }
2120 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002121 }
2122
Johnathan Manteyb87034e2019-09-16 10:50:50 -07002123 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
2124 {
2125 return getLanOem(channel, parameter, set, block);
2126 }
2127
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002128 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002129}
2130
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002131} // namespace transport
2132} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302133
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002134void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05302135
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002136void register_netfn_transport_functions()
2137{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002138 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2139 ipmi::transport::cmdSetLanConfigParameters,
2140 ipmi::Privilege::Admin, ipmi::transport::setLan);
2141 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
2142 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08002143 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002144}