blob: 777171c3ce3c58c50c0a79b8101cfa09b70c5ee6 [file] [log] [blame]
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001#include "app/channel.hpp"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include <arpa/inet.h>
William A. Kennington IIIc514d872019-04-06 18:19:38 -07004#include <netinet/ether.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07005
William A. Kennington IIIc514d872019-04-06 18:19:38 -07006#include <array>
7#include <bitset>
8#include <cinttypes>
9#include <cstdint>
10#include <cstring>
Johnathan Manteyaffadb52019-10-07 10:13:53 -070011#include <fstream>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070012#include <functional>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070013#include <ipmid/api.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070014#include <ipmid/message.hpp>
15#include <ipmid/message/types.hpp>
16#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070017#include <ipmid/utils.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070018#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <phosphor-logging/elog-errors.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070020#include <phosphor-logging/elog.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070021#include <phosphor-logging/log.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070022#include <sdbusplus/bus.hpp>
23#include <sdbusplus/exception.hpp>
tomjose26e17732016-03-03 08:52:51 -060024#include <string>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070025#include <string_view>
26#include <type_traits>
27#include <unordered_map>
28#include <unordered_set>
29#include <user_channel/channel_layer.hpp>
30#include <utility>
31#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070032#include <xyz/openbmc_project/Common/error.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070033#include <xyz/openbmc_project/Network/IP/server.hpp>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070034#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070035
William A. Kennington IIIc514d872019-04-06 18:19:38 -070036using phosphor::logging::commit;
37using phosphor::logging::elog;
38using phosphor::logging::entry;
39using phosphor::logging::level;
40using phosphor::logging::log;
41using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
42using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070043using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070044
Johnathan Manteyaffadb52019-10-07 10:13:53 -070045namespace cipher
46{
47
48std::vector<uint8_t> getCipherList()
49{
50 std::vector<uint8_t> cipherList;
51
52 std::ifstream jsonFile(cipher::configFile);
53 if (!jsonFile.is_open())
54 {
55 log<level::ERR>("Channel Cipher suites file not found");
56 elog<InternalFailure>();
57 }
58
59 auto data = Json::parse(jsonFile, nullptr, false);
60 if (data.is_discarded())
61 {
62 log<level::ERR>("Parsing channel cipher suites JSON failed");
63 elog<InternalFailure>();
64 }
65
66 // Byte 1 is reserved
67 cipherList.push_back(0x00);
68
69 for (const auto& record : data)
70 {
71 cipherList.push_back(record.value(cipher, 0));
72 }
73
74 return cipherList;
75}
76} // namespace cipher
77
78namespace ipmi
79{
80namespace transport
81{
82
William A. Kennington IIIc514d872019-04-06 18:19:38 -070083// LAN Handler specific response codes
84constexpr Cc ccParamNotSupported = 0x80;
85constexpr Cc ccParamSetLocked = 0x81;
86constexpr Cc ccParamReadOnly = 0x82;
87
88// VLANs are a 12-bit value
89constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
90constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
91
92// D-Bus Network Daemon definitions
93constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
94constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
95
96constexpr auto INTF_SYSTEMCONFIG =
97 "xyz.openbmc_project.Network.SystemConfiguration";
98constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
99constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
100constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
101constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700102constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
103constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
104 "xyz.openbmc_project.Network.Neighbor.CreateStatic";
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700105constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
106constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
107
108/** @brief Generic paramters for different address families */
109template <int family>
110struct AddrFamily
111{
112};
113
114/** @brief Parameter specialization for IPv4 */
115template <>
116struct AddrFamily<AF_INET>
117{
118 using addr = in_addr;
119 static constexpr auto protocol = IP::Protocol::IPv4;
120 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
121 static constexpr uint8_t defaultPrefix = 32;
122 static constexpr char propertyGateway[] = "DefaultGateway";
123};
124
125/** @brief Valid address origins for IPv4 */
126const std::unordered_set<IP::AddressOrigin> originsV4 = {
127 IP::AddressOrigin::Static,
128 IP::AddressOrigin::DHCP,
129};
130
131/** @brief Interface IP Address configuration parameters */
132template <int family>
133struct IfAddr
134{
135 std::string path;
136 typename AddrFamily<family>::addr address;
137 IP::AddressOrigin origin;
138 uint8_t prefix;
139};
140
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700141/** @brief Interface Neighbor configuration parameters */
142template <int family>
143struct IfNeigh
144{
145 std::string path;
146 typename AddrFamily<family>::addr ip;
147 ether_addr mac;
148};
149
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700150/** @brief IPMI LAN Parameters */
151enum class LanParam : uint8_t
152{
153 SetStatus = 0,
154 AuthSupport = 1,
155 AuthEnables = 2,
156 IP = 3,
157 IPSrc = 4,
158 MAC = 5,
159 SubnetMask = 6,
160 Gateway1 = 12,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700161 Gateway1MAC = 13,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700162 VLANId = 20,
163 CiphersuiteSupport = 22,
164 CiphersuiteEntries = 23,
165};
166
167/** @brief IPMI IP Origin Types */
168enum class IPSrc : uint8_t
169{
170 Unspecified = 0,
171 Static = 1,
172 DHCP = 2,
173 BIOS = 3,
174 BMC = 4,
175};
176
177/** @brief IPMI Set Status */
178enum class SetStatus : uint8_t
179{
180 Complete = 0,
181 InProgress = 1,
182 Commit = 2,
183};
184
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700185/** @brief A trivial helper used to determine if two PODs are equal
186 *
187 * @params[in] a - The first object to compare
188 * @params[in] b - The second object to compare
189 * @return True if the objects are the same bytewise
190 */
191template <typename T>
192bool equal(const T& a, const T& b)
193{
194 static_assert(std::is_trivially_copyable_v<T>);
195 return std::memcmp(&a, &b, sizeof(T)) == 0;
196}
197
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700198/** @brief Copies bytes from an array into a trivially copyable container
199 *
200 * @params[out] t - The container receiving the data
201 * @params[in] bytes - The data to copy
202 */
203template <size_t N, typename T>
204void copyInto(T& t, const std::array<uint8_t, N>& bytes)
205{
206 static_assert(std::is_trivially_copyable_v<T>);
207 static_assert(N == sizeof(T));
208 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800209}
210
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700211/** @brief Gets a generic view of the bytes in the input container
212 *
213 * @params[in] t - The data to reference
214 * @return A string_view referencing the bytes in the container
215 */
216template <typename T>
217std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600218{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700219 static_assert(std::is_trivially_copyable_v<T>);
220 return {reinterpret_cast<const char*>(&t), sizeof(T)};
221}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530222
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700223/** @brief The dbus parameters for the interface corresponding to a channel
224 * This helps reduce the number of mapper lookups we need for each
225 * query and simplifies finding the VLAN interface if needed.
226 */
227struct ChannelParams
228{
229 /** @brief The channel ID */
230 int id;
231 /** @brief channel name for the interface */
232 std::string ifname;
233 /** @brief Name of the service on the bus */
234 std::string service;
235 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
236 std::string ifPath;
237 /** @brief Logical adapter path used for address assignment */
238 std::string logicalPath;
239};
240
241/** @brief Determines the ethernet interface name corresponding to a channel
242 * Tries to map a VLAN object first so that the address information
243 * is accurate. Otherwise it gets the standard ethernet interface.
244 *
245 * @param[in] bus - The bus object used for lookups
246 * @param[in] channel - The channel id corresponding to an ethernet interface
247 * @return Ethernet interface service and object path if it exists
248 */
249std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
250 uint8_t channel)
251{
252 auto ifname = getChannelName(channel);
253 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800254 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700255 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800256 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800257
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700258 // Enumerate all VLAN + ETHERNET interfaces
259 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
260 "GetSubTree");
261 req.append(PATH_ROOT, 0,
262 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
263 auto reply = bus.call(req);
264 ObjectTree objs;
265 reply.read(objs);
266
267 ChannelParams params;
268 for (const auto& [path, impls] : objs)
269 {
270 if (path.find(ifname) == path.npos)
271 {
272 continue;
273 }
274 for (const auto& [service, intfs] : impls)
275 {
276 bool vlan = false;
277 bool ethernet = false;
278 for (const auto& intf : intfs)
279 {
280 if (intf == INTF_VLAN)
281 {
282 vlan = true;
283 }
284 else if (intf == INTF_ETHERNET)
285 {
286 ethernet = true;
287 }
288 }
289 if (params.service.empty() && (vlan || ethernet))
290 {
291 params.service = service;
292 }
293 if (params.ifPath.empty() && !vlan && ethernet)
294 {
295 params.ifPath = path;
296 }
297 if (params.logicalPath.empty() && vlan)
298 {
299 params.logicalPath = path;
300 }
301 }
302 }
303
304 // We must have a path for the underlying interface
305 if (params.ifPath.empty())
306 {
307 return std::nullopt;
308 }
309 // We don't have a VLAN so the logical path is the same
310 if (params.logicalPath.empty())
311 {
312 params.logicalPath = params.ifPath;
313 }
314
315 params.id = channel;
316 params.ifname = std::move(ifname);
317 return std::move(params);
318}
319
320/** @brief A trivial helper around maybeGetChannelParams() that throws an
321 * exception when it is unable to acquire parameters for the channel.
322 *
323 * @param[in] bus - The bus object used for lookups
324 * @param[in] channel - The channel id corresponding to an ethernet interface
325 * @return Ethernet interface service and object path
326 */
327ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
328{
329 auto params = maybeGetChannelParams(bus, channel);
330 if (!params)
331 {
332 log<level::ERR>("Failed to get channel params",
333 entry("CHANNEL=%" PRIu8, channel));
334 elog<InternalFailure>();
335 }
336 return std::move(*params);
337}
338
339/** @brief Wraps the phosphor logging method to insert some additional metadata
340 *
341 * @param[in] params - The parameters for the channel
342 * ...
343 */
344template <auto level, typename... Args>
345auto logWithChannel(const ChannelParams& params, Args&&... args)
346{
347 return log<level>(std::forward<Args>(args)...,
348 entry("CHANNEL=%d", params.id),
349 entry("IFNAME=%s", params.ifname.c_str()));
350}
351template <auto level, typename... Args>
352auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
353{
354 if (params)
355 {
356 return logWithChannel<level>(*params, std::forward<Args>(args)...);
357 }
358 return log<level>(std::forward<Args>(args)...);
359}
360
361/** @brief Trivializes using parameter getter functions by providing a bus
362 * and channel parameters automatically.
363 *
364 * @param[in] channel - The channel id corresponding to an ethernet interface
365 * ...
366 */
367template <auto func, typename... Args>
368auto channelCall(uint8_t channel, Args&&... args)
369{
370 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
371 auto params = getChannelParams(bus, channel);
372 return std::invoke(func, bus, params, std::forward<Args>(args)...);
373}
374
375/** @brief Determines if the ethernet interface is using DHCP
376 *
377 * @param[in] bus - The bus object used for lookups
378 * @param[in] params - The parameters for the channel
379 * @return True if DHCP is enabled, false otherwise
380 */
381bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
382{
383 return std::get<bool>(getDbusProperty(
384 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
385}
386
387/** @brief Sets the system value for DHCP on the given interface
388 *
389 * @param[in] bus - The bus object used for lookups
390 * @param[in] params - The parameters for the channel
391 * @param[in] on - Whether or not to enable DHCP
392 */
393void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
394 bool on)
395{
396 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
397 "DHCPEnabled", on);
398}
399
400/** @brief Converts a human readable MAC string into MAC bytes
401 *
402 * @param[in] mac - The MAC string
403 * @return MAC in bytes
404 */
405ether_addr stringToMAC(const char* mac)
406{
407 const ether_addr* ret = ether_aton(mac);
408 if (ret == nullptr)
409 {
410 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
411 elog<InternalFailure>();
412 }
413 return *ret;
414}
415
416/** @brief Determines the MAC of the ethernet interface
417 *
418 * @param[in] bus - The bus object used for lookups
419 * @param[in] params - The parameters for the channel
420 * @return The configured mac address
421 */
422ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
423{
424 auto macStr = std::get<std::string>(getDbusProperty(
425 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
426 return stringToMAC(macStr.c_str());
427}
428
429/** @brief Sets the system value for MAC address on the given interface
430 *
431 * @param[in] bus - The bus object used for lookups
432 * @param[in] params - The parameters for the channel
433 * @param[in] mac - MAC address to apply
434 */
435void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
436 const ether_addr& mac)
437{
438 std::string macStr = ether_ntoa(&mac);
439 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
440 macStr);
441}
442
443/** @brief Turns an IP address string into the network byte order form
444 * NOTE: This version strictly validates family matches
445 *
446 * @param[in] address - The string form of the address
447 * @return A network byte order address or none if conversion failed
448 */
449template <int family>
450std::optional<typename AddrFamily<family>::addr>
451 maybeStringToAddr(const char* address)
452{
453 typename AddrFamily<family>::addr ret;
454 if (inet_pton(family, address, &ret) == 1)
455 {
456 return ret;
457 }
458 return std::nullopt;
459}
460
461/** @brief Turns an IP address string into the network byte order form
462 * NOTE: This version strictly validates family matches
463 *
464 * @param[in] address - The string form of the address
465 * @return A network byte order address
466 */
467template <int family>
468typename AddrFamily<family>::addr stringToAddr(const char* address)
469{
470 auto ret = maybeStringToAddr<family>(address);
471 if (!ret)
472 {
473 log<level::ERR>("Failed to convert IP Address",
474 entry("FAMILY=%d", family),
475 entry("ADDRESS=%s", address));
476 elog<InternalFailure>();
477 }
478 return *ret;
479}
480
481/** @brief Turns an IP address in network byte order into a string
482 *
483 * @param[in] address - The string form of the address
484 * @return A network byte order address
485 */
486template <int family>
487std::string addrToString(const typename AddrFamily<family>::addr& address)
488{
489 std::string ret(AddrFamily<family>::maxStrLen, '\0');
490 inet_ntop(family, &address, ret.data(), ret.size());
491 ret.resize(strlen(ret.c_str()));
492 return ret;
493}
494
495/** @brief Retrieves the current gateway for the address family on the system
496 * NOTE: The gateway is currently system wide and not per channel
497 *
498 * @param[in] bus - The bus object used for lookups
499 * @param[in] params - The parameters for the channel
500 * @return An address representing the gateway address if it exists
501 */
502template <int family>
503std::optional<typename AddrFamily<family>::addr>
504 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
505{
506 auto gatewayStr = std::get<std::string>(getDbusProperty(
507 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
508 AddrFamily<family>::propertyGateway));
509 if (gatewayStr.empty())
510 {
511 return std::nullopt;
512 }
513 return stringToAddr<family>(gatewayStr.c_str());
514}
515
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700516/** @brief A lazy lookup mechanism for iterating over object properties stored
517 * in DBus. This will only perform the object lookup when needed, and
518 * retains a cache of previous lookups to speed up future iterations.
519 */
520class ObjectLookupCache
521{
522 public:
523 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
524
525 /** @brief Creates a new ObjectLookupCache for the interface on the bus
526 * NOTE: The inputs to this object must outlive the object since
527 * they are only referenced by it.
528 *
529 * @param[in] bus - The bus object used for lookups
530 * @param[in] params - The parameters for the channel
531 * @param[in] intf - The interface we are looking up
532 */
533 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
534 const char* intf) :
535 bus(bus),
536 params(params), intf(intf),
537 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
538 {
539 }
540
541 class iterator : public ObjectTree::const_iterator
542 {
543 public:
544 using value_type = PropertiesCache::value_type;
545
546 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
547 ObjectTree::const_iterator(it), container(container),
548 ret(container.cache.end())
549 {
550 }
551 value_type& operator*()
552 {
553 ret = container.get(ObjectTree::const_iterator::operator*().first);
554 return *ret;
555 }
556 value_type* operator->()
557 {
558 return &operator*();
559 }
560
561 private:
562 ObjectLookupCache& container;
563 PropertiesCache::iterator ret;
564 };
565
566 iterator begin() noexcept
567 {
568 return iterator(objs.begin(), *this);
569 }
570
571 iterator end() noexcept
572 {
573 return iterator(objs.end(), *this);
574 }
575
576 private:
577 sdbusplus::bus::bus& bus;
578 const ChannelParams& params;
579 const char* const intf;
580 const ObjectTree objs;
581 PropertiesCache cache;
582
583 /** @brief Gets a cached copy of the object properties if possible
584 * Otherwise performs a query on DBus to look them up
585 *
586 * @param[in] path - The object path to lookup
587 * @return An iterator for the specified object path + properties
588 */
589 PropertiesCache::iterator get(const std::string& path)
590 {
591 auto it = cache.find(path);
592 if (it != cache.end())
593 {
594 return it;
595 }
596 auto properties = getAllDbusProperties(bus, params.service, path, intf);
597 return cache.insert({path, std::move(properties)}).first;
598 }
599};
600
601/** @brief Searches the ip object lookup cache for an address matching
602 * the input parameters. NOTE: The index lacks stability across address
603 * changes since the network daemon has no notion of stable indicies.
604 *
605 * @param[in] bus - The bus object used for lookups
606 * @param[in] params - The parameters for the channel
607 * @param[in] idx - The index of the desired address on the interface
608 * @param[in] origins - The allowed origins for the address objects
609 * @param[in] ips - The object lookup cache holding all of the address info
610 * @return The address and prefix if it was found
611 */
612template <int family>
613std::optional<IfAddr<family>>
614 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
615 uint8_t idx,
616 const std::unordered_set<IP::AddressOrigin>& origins,
617 ObjectLookupCache& ips)
618{
619 for (const auto& [path, properties] : ips)
620 {
621 const auto& addrStr = std::get<std::string>(properties.at("Address"));
622 auto addr = maybeStringToAddr<family>(addrStr.c_str());
623 if (!addr)
624 {
625 continue;
626 }
627
628 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
629 std::get<std::string>(properties.at("Origin")));
630 if (origins.find(origin) == origins.end())
631 {
632 continue;
633 }
634
635 if (idx > 0)
636 {
637 idx--;
638 continue;
639 }
640
641 IfAddr<family> ifaddr;
642 ifaddr.path = path;
643 ifaddr.address = *addr;
644 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
645 ifaddr.origin = origin;
646 return std::move(ifaddr);
647 }
648
649 return std::nullopt;
650}
651
652/** @brief Trivial helper around findIfAddr that simplifies calls
653 * for one off lookups. Don't use this if you intend to do multiple
654 * lookups at a time.
655 *
656 * @param[in] bus - The bus object used for lookups
657 * @param[in] params - The parameters for the channel
658 * @param[in] idx - The index of the desired address on the interface
659 * @param[in] origins - The allowed origins for the address objects
660 * @return The address and prefix if it was found
661 */
662template <int family>
663auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
664 uint8_t idx,
665 const std::unordered_set<IP::AddressOrigin>& origins)
666{
667 ObjectLookupCache ips(bus, params, INTF_IP);
668 return findIfAddr<family>(bus, params, idx, origins, ips);
669}
670
671/** @brief Deletes the dbus object. Ignores empty objects or objects that are
672 * missing from the bus.
673 *
674 * @param[in] bus - The bus object used for lookups
675 * @param[in] service - The name of the service
676 * @param[in] path - The path of the object to delete
677 */
678void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
679 const std::string& path)
680{
681 if (path.empty())
682 {
683 return;
684 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530685 try
tomjose26e17732016-03-03 08:52:51 -0600686 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700687 auto req = bus.new_method_call(service.c_str(), path.c_str(),
688 ipmi::DELETE_INTERFACE, "Delete");
689 bus.call_noreply(req);
690 }
691 catch (const sdbusplus::exception::SdBusError& e)
692 {
693 if (strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600694 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700695 // We want to rethrow real errors
696 throw;
tomjose26e17732016-03-03 08:52:51 -0600697 }
698 }
tomjose26e17732016-03-03 08:52:51 -0600699}
700
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700701/** @brief Sets the address info configured for the interface
702 * If a previous address path exists then it will be removed
703 * before the new address is added.
704 *
705 * @param[in] bus - The bus object used for lookups
706 * @param[in] params - The parameters for the channel
707 * @param[in] address - The address of the new IP
708 * @param[in] prefix - The prefix of the new IP
709 */
710template <int family>
711void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
712 const typename AddrFamily<family>::addr& address,
713 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530714{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700715 auto newreq =
716 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
717 INTF_IP_CREATE, "IP");
718 std::string protocol =
719 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
720 AddrFamily<family>::protocol);
721 newreq.append(protocol, addrToString<family>(address), prefix, "");
722 bus.call_noreply(newreq);
723}
Tom Josepha30c8d32018-03-22 02:15:03 +0530724
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700725/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
726 *
727 * @param[in] bus - The bus object used for lookups
728 * @param[in] params - The parameters for the channel
729 * @return The address and prefix if found
730 */
731auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530732{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700733 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
734}
Tom Josepha30c8d32018-03-22 02:15:03 +0530735
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700736/** @brief Reconfigures the IPv4 address info configured for the interface
737 *
738 * @param[in] bus - The bus object used for lookups
739 * @param[in] params - The parameters for the channel
740 * @param[in] address - The new address if specified
741 * @param[in] prefix - The new address prefix if specified
742 */
743void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
744 const std::optional<in_addr>& address,
745 std::optional<uint8_t> prefix)
746{
747 auto ifaddr = getIfAddr4(bus, params);
748 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530749 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700750 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530751 elog<InternalFailure>();
752 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700753 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
754 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530755 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700756 fallbackPrefix = ifaddr->prefix;
757 deleteObjectIfExists(bus, params.service, ifaddr->path);
758 }
759 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
760 prefix.value_or(fallbackPrefix));
761}
762
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700763template <int family>
764std::optional<IfNeigh<family>>
765 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
766 const typename AddrFamily<family>::addr& ip,
767 ObjectLookupCache& neighbors)
768{
769 const auto state =
770 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
771 Neighbor::State::Permanent);
772 for (const auto& [path, neighbor] : neighbors)
773 {
774 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
775 auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
776 if (!neighIP)
777 {
778 continue;
779 }
780 if (!equal(*neighIP, ip))
781 {
782 continue;
783 }
784 if (state != std::get<std::string>(neighbor.at("State")))
785 {
786 continue;
787 }
788
789 IfNeigh<family> ret;
790 ret.path = path;
791 ret.ip = ip;
792 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
793 ret.mac = stringToMAC(macStr.c_str());
794 return std::move(ret);
795 }
796
797 return std::nullopt;
798}
799
800template <int family>
801void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
802 const typename AddrFamily<family>::addr& address,
803 const ether_addr& mac)
804{
805 auto newreq =
806 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
807 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
808 std::string macStr = ether_ntoa(&mac);
809 newreq.append(addrToString<family>(address), macStr);
810 bus.call_noreply(newreq);
811}
812
813/** @brief Sets the system wide value for the default gateway
814 *
815 * @param[in] bus - The bus object used for lookups
816 * @param[in] params - The parameters for the channel
817 * @param[in] gateway - Gateway address to apply
818 */
819template <int family>
820void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
821 const typename AddrFamily<family>::addr& address)
822{
823 // Save the old gateway MAC address if it exists so we can recreate it
824 auto gateway = getGatewayProperty<family>(bus, params);
825 std::optional<IfNeigh<family>> neighbor;
826 if (gateway)
827 {
828 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
829 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
830 }
831
832 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
833 AddrFamily<family>::propertyGateway,
834 addrToString<family>(address));
835
836 // Restore the gateway MAC if we had one
837 if (neighbor)
838 {
839 deleteObjectIfExists(bus, params.service, neighbor->path);
840 createNeighbor<family>(bus, params, address, neighbor->mac);
841 }
842}
843
844template <int family>
845std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
846 const ChannelParams& params,
847 ObjectLookupCache& neighbors)
848{
849 auto gateway = getGatewayProperty<family>(bus, params);
850 if (!gateway)
851 {
852 return std::nullopt;
853 }
854
855 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
856}
857
858template <int family>
859std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
860 const ChannelParams& params)
861{
862 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
863 return findGatewayNeighbor<family>(bus, params, neighbors);
864}
865
866template <int family>
867void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
868 const ChannelParams& params, const ether_addr& mac)
869{
870 auto gateway = getGatewayProperty<family>(bus, params);
871 if (!gateway)
872 {
873 log<level::ERR>("Tried to set Gateway MAC without Gateway");
874 elog<InternalFailure>();
875 }
876
877 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
878 auto neighbor =
879 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
880 if (neighbor)
881 {
882 deleteObjectIfExists(bus, params.service, neighbor->path);
883 }
884
885 createNeighbor<family>(bus, params, *gateway, mac);
886}
887
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700888/** @brief Gets the vlan ID configured on the interface
889 *
890 * @param[in] bus - The bus object used for lookups
891 * @param[in] params - The parameters for the channel
892 * @return VLAN id or the standard 0 for no VLAN
893 */
894uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
895{
896 // VLAN devices will always have a separate logical object
897 if (params.ifPath == params.logicalPath)
898 {
899 return 0;
900 }
901
902 auto vlan = std::get<uint32_t>(getDbusProperty(
903 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
904 if ((vlan & VLAN_VALUE_MASK) != vlan)
905 {
906 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
907 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530908 elog<InternalFailure>();
909 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700910 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530911}
912
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700913/** @brief Deletes all of the possible configuration parameters for a channel
914 *
915 * @param[in] bus - The bus object used for lookups
916 * @param[in] params - The parameters for the channel
917 */
918void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500919{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700920 // Delete all objects associated with the interface
921 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
922 "GetSubTree");
923 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
924 auto objreply = bus.call(objreq);
925 ObjectTree objs;
926 objreply.read(objs);
927 for (const auto& [path, impls] : objs)
928 {
929 if (path.find(params.ifname) == path.npos)
930 {
931 continue;
932 }
933 for (const auto& [service, intfs] : impls)
934 {
935 deleteObjectIfExists(bus, service, path);
936 }
937 // Update params to reflect the deletion of vlan
938 if (path == params.logicalPath)
939 {
940 params.logicalPath = params.ifPath;
941 }
942 }
943
944 // Clear out any settings on the lower physical interface
945 setDHCPProperty(bus, params, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500946}
947
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700948/** @brief Creates a new VLAN on the specified interface
949 *
950 * @param[in] bus - The bus object used for lookups
951 * @param[in] params - The parameters for the channel
952 * @param[in] vlan - The id of the new vlan
953 */
954void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530955{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700956 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530957 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700958 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530959 }
960
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700961 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
962 INTF_VLAN_CREATE, "VLAN");
963 req.append(params.ifname, static_cast<uint32_t>(vlan));
964 auto reply = bus.call(req);
965 sdbusplus::message::object_path newPath;
966 reply.read(newPath);
967 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530968}
969
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700970/** @brief Performs the necessary reconfiguration to change the VLAN
971 *
972 * @param[in] bus - The bus object used for lookups
973 * @param[in] params - The parameters for the channel
974 * @param[in] vlan - The new vlan id to use
975 */
976void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
977 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500978{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700979 // Unfortunatetly we don't have built-in functions to migrate our interface
980 // customizations to new VLAN interfaces, or have some kind of decoupling.
981 // We therefore must retain all of our old information, setup the new VLAN
982 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800983
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700984 // Save info from the old logical interface
985 ObjectLookupCache ips(bus, params, INTF_IP);
986 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
987 auto dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700988 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
989 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500990
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700991 deconfigureChannel(bus, params);
992 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500993
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700994 // Re-establish the saved settings
995 setDHCPProperty(bus, params, dhcp);
996 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800997 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700998 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800999 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001000 if (neighbor4)
1001 {
1002 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
1003 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001004}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08001005
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001006/** @brief Turns a prefix into a netmask
1007 *
1008 * @param[in] prefix - The prefix length
1009 * @return The netmask
1010 */
1011in_addr prefixToNetmask(uint8_t prefix)
1012{
1013 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001014 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001015 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
1016 elog<InternalFailure>();
1017 }
1018 if (prefix == 0)
1019 {
1020 // Avoids 32-bit lshift by 32 UB
1021 return {};
1022 }
1023 return {htobe32(~UINT32_C(0) << (32 - prefix))};
1024}
1025
1026/** @brief Turns a a netmask into a prefix length
1027 *
1028 * @param[in] netmask - The netmask in byte form
1029 * @return The prefix length
1030 */
1031uint8_t netmaskToPrefix(in_addr netmask)
1032{
1033 uint32_t x = be32toh(netmask.s_addr);
1034 if ((~x & (~x + 1)) != 0)
1035 {
1036 char maskStr[INET_ADDRSTRLEN];
1037 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
1038 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
1039 elog<InternalFailure>();
1040 }
1041 return 32 - __builtin_ctz(x);
1042}
1043
1044// We need to store this value so it can be returned to the client
1045// It is volatile so safe to store in daemon memory.
1046static std::unordered_map<uint8_t, SetStatus> setStatus;
1047
1048// Until we have good support for fixed versions of IPMI tool
1049// we need to return the VLAN id for disabled VLANs. The value is only
1050// used for verification that a disable operation succeeded and will only
1051// be sent if our system indicates that vlans are disabled.
1052static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
1053
1054/** @brief Gets the set status for the channel if it exists
1055 * Otherise populates and returns the default value.
1056 *
1057 * @param[in] channel - The channel id corresponding to an ethernet interface
1058 * @return A reference to the SetStatus for the channel
1059 */
1060SetStatus& getSetStatus(uint8_t channel)
1061{
1062 auto it = setStatus.find(channel);
1063 if (it != setStatus.end())
1064 {
1065 return it->second;
1066 }
1067 return setStatus[channel] = SetStatus::Complete;
1068}
1069
1070RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
1071 message::Payload& req)
1072{
1073 auto channel = static_cast<uint8_t>(channelBits);
1074 if (!doesDeviceExist(channel))
1075 {
1076 req.trailingOk = true;
1077 return responseInvalidFieldRequest();
1078 }
1079
1080 switch (static_cast<LanParam>(parameter))
1081 {
1082 case LanParam::SetStatus:
1083 {
1084 uint2_t flag;
1085 uint6_t rsvd;
1086 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1087 {
1088 return responseReqDataLenInvalid();
1089 }
1090 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
1091 switch (status)
1092 {
1093 case SetStatus::Complete:
1094 {
1095 getSetStatus(channel) = status;
1096 return responseSuccess();
1097 }
1098 case SetStatus::InProgress:
1099 {
1100 auto& storedStatus = getSetStatus(channel);
1101 if (storedStatus == SetStatus::InProgress)
1102 {
1103 return response(ccParamSetLocked);
1104 }
1105 storedStatus = status;
1106 return responseSuccess();
1107 }
1108 case SetStatus::Commit:
1109 if (getSetStatus(channel) != SetStatus::InProgress)
1110 {
1111 return responseInvalidFieldRequest();
1112 }
1113 return responseSuccess();
1114 }
1115 return response(ccParamNotSupported);
1116 }
1117 case LanParam::AuthSupport:
1118 {
1119 req.trailingOk = true;
1120 return response(ccParamReadOnly);
1121 }
1122 case LanParam::AuthEnables:
1123 {
1124 req.trailingOk = true;
1125 return response(ccParamNotSupported);
1126 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001127 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -06001128 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001129 in_addr ip;
1130 std::array<uint8_t, sizeof(ip)> bytes;
1131 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1132 {
1133 return responseReqDataLenInvalid();
1134 }
1135 copyInto(ip, bytes);
1136 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
1137 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301138 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001139 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301140 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001141 uint4_t flag;
1142 uint4_t rsvd;
1143 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
1144 {
1145 return responseReqDataLenInvalid();
1146 }
1147 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
1148 {
1149 case IPSrc::DHCP:
1150 {
1151 channelCall<setDHCPProperty>(channel, true);
1152 return responseSuccess();
1153 }
1154 case IPSrc::Unspecified:
1155 case IPSrc::Static:
1156 case IPSrc::BIOS:
1157 case IPSrc::BMC:
1158 {
1159 channelCall<setDHCPProperty>(channel, false);
1160 return responseSuccess();
1161 }
1162 }
1163 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05301164 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001165 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +05301166 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001167 ether_addr mac;
1168 std::array<uint8_t, sizeof(mac)> bytes;
1169 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301170 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001171 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301172 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001173 copyInto(mac, bytes);
1174 channelCall<setMACProperty>(channel, mac);
1175 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301176 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001177 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301178 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001179 in_addr netmask;
1180 std::array<uint8_t, sizeof(netmask)> bytes;
1181 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301182 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001183 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301184 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001185 copyInto(netmask, bytes);
1186 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1187 netmaskToPrefix(netmask));
1188 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301189 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001190 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301191 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001192 in_addr gateway;
1193 std::array<uint8_t, sizeof(gateway)> bytes;
1194 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1195 {
1196 return responseReqDataLenInvalid();
1197 }
1198 copyInto(gateway, bytes);
1199 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1200 return responseSuccess();
1201 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001202 case LanParam::Gateway1MAC:
1203 {
1204 ether_addr gatewayMAC;
1205 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1206 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1207 {
1208 return responseReqDataLenInvalid();
1209 }
1210 copyInto(gatewayMAC, bytes);
1211 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1212 return responseSuccess();
1213 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001214 case LanParam::VLANId:
1215 {
1216 uint16_t vlanData;
1217 if (req.unpack(vlanData) != 0 || !req.fullyUnpacked())
1218 {
1219 return responseReqDataLenInvalid();
1220 }
1221 if ((vlanData & VLAN_ENABLE_FLAG) == 0)
1222 {
1223 lastDisabledVlan[channel] = vlanData & VLAN_VALUE_MASK;
1224 vlanData = 0;
1225 }
1226 channelCall<reconfigureVLAN>(channel, vlanData & VLAN_VALUE_MASK);
1227 return responseSuccess();
1228 }
1229 case LanParam::CiphersuiteSupport:
1230 case LanParam::CiphersuiteEntries:
1231 {
1232 req.trailingOk = true;
1233 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301234 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301235 }
vishwa1eaea4f2016-02-26 11:57:40 -06001236
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001237 req.trailingOk = true;
1238 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001239}
1240
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001241RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
1242 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301243{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001244 message::Payload ret;
1245 constexpr uint8_t current_revision = 0x11;
1246 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001247
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001248 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301249 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001250 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301251 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001252
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001253 auto channel = static_cast<uint8_t>(channelBits);
1254 if (!doesDeviceExist(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001255 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001256 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001257 }
1258
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001259 static std::vector<uint8_t> cipherList;
1260 static bool listInit = false;
1261 if (!listInit)
1262 {
1263 try
1264 {
1265 cipherList = cipher::getCipherList();
1266 listInit = true;
1267 }
1268 catch (const std::exception& e)
1269 {
1270 }
1271 }
1272
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001273 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301274 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001275 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301276 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001277 SetStatus status;
1278 try
1279 {
1280 status = setStatus.at(channel);
1281 }
1282 catch (const std::out_of_range&)
1283 {
1284 status = SetStatus::Complete;
1285 }
1286 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1287 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301288 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001289 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301290 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001291 std::bitset<6> support;
1292 ret.pack(support, uint2_t{});
1293 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301294 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001295 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001296 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001297 std::bitset<6> enables;
1298 ret.pack(enables, uint2_t{}); // Callback
1299 ret.pack(enables, uint2_t{}); // User
1300 ret.pack(enables, uint2_t{}); // Operator
1301 ret.pack(enables, uint2_t{}); // Admin
1302 ret.pack(enables, uint2_t{}); // OEM
1303 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001304 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001305 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001306 {
1307 auto ifaddr = channelCall<getIfAddr4>(channel);
1308 in_addr addr{};
1309 if (ifaddr)
1310 {
1311 addr = ifaddr->address;
1312 }
1313 ret.pack(dataRef(addr));
1314 return responseSuccess(std::move(ret));
1315 }
1316 case LanParam::IPSrc:
1317 {
1318 auto src = IPSrc::Static;
1319 if (channelCall<getDHCPProperty>(channel))
1320 {
1321 src = IPSrc::DHCP;
1322 }
1323 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1324 return responseSuccess(std::move(ret));
1325 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001326 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001327 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001328 ether_addr mac = channelCall<getMACProperty>(channel);
1329 ret.pack(dataRef(mac));
1330 return responseSuccess(std::move(ret));
1331 }
1332 case LanParam::SubnetMask:
1333 {
1334 auto ifaddr = channelCall<getIfAddr4>(channel);
1335 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1336 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301337 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001338 prefix = ifaddr->prefix;
1339 }
1340 in_addr netmask = prefixToNetmask(prefix);
1341 ret.pack(dataRef(netmask));
1342 return responseSuccess(std::move(ret));
1343 }
1344 case LanParam::Gateway1:
1345 {
1346 auto gateway =
1347 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1348 in_addr{});
1349 ret.pack(dataRef(gateway));
1350 return responseSuccess(std::move(ret));
1351 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001352 case LanParam::Gateway1MAC:
1353 {
1354 ether_addr mac{};
1355 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1356 if (neighbor)
1357 {
1358 mac = neighbor->mac;
1359 }
1360 ret.pack(dataRef(mac));
1361 return responseSuccess(std::move(ret));
1362 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001363 case LanParam::VLANId:
1364 {
1365 uint16_t vlan = channelCall<getVLANProperty>(channel);
1366 if (vlan != 0)
1367 {
1368 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301369 }
1370 else
1371 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001372 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301373 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001374 ret.pack(vlan);
1375 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001376 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001377 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001378 {
1379 if (!listInit)
1380 {
1381 return responseUnspecifiedError();
1382 }
1383 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1384 return responseSuccess(std::move(ret));
1385 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001386 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001387 {
1388 if (!listInit)
1389 {
1390 return responseUnspecifiedError();
1391 }
1392 ret.pack(cipherList);
1393 return responseSuccess(std::move(ret));
1394 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001395 }
1396
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001397 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001398}
1399
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001400} // namespace transport
1401} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301402
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001403void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301404
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001405void register_netfn_transport_functions()
1406{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001407 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1408 ipmi::transport::cmdSetLanConfigParameters,
1409 ipmi::Privilege::Admin, ipmi::transport::setLan);
1410 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1411 ipmi::transport::cmdGetLanConfigParameters,
1412 ipmi::Privilege::Admin, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001413}