blob: e88eb630694359494a0e8038688a0b8b0cd9dc81 [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include <arpa/inet.h>
William A. Kennington IIIc514d872019-04-06 18:19:38 -07002#include <netinet/ether.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07003
William A. Kennington IIIc514d872019-04-06 18:19:38 -07004#include <array>
5#include <bitset>
6#include <cinttypes>
7#include <cstdint>
8#include <cstring>
9#include <functional>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070010#include <ipmid/api.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070011#include <ipmid/message.hpp>
12#include <ipmid/message/types.hpp>
13#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070014#include <ipmid/utils.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070015#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070016#include <phosphor-logging/elog-errors.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070017#include <phosphor-logging/elog.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070018#include <phosphor-logging/log.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070019#include <sdbusplus/bus.hpp>
20#include <sdbusplus/exception.hpp>
tomjose26e17732016-03-03 08:52:51 -060021#include <string>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070022#include <string_view>
23#include <type_traits>
24#include <unordered_map>
25#include <unordered_set>
26#include <user_channel/channel_layer.hpp>
27#include <utility>
28#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070029#include <xyz/openbmc_project/Common/error.hpp>
William A. Kennington IIIc514d872019-04-06 18:19:38 -070030#include <xyz/openbmc_project/Network/IP/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070031
William A. Kennington IIIc514d872019-04-06 18:19:38 -070032namespace ipmi
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080033{
William A. Kennington IIIc514d872019-04-06 18:19:38 -070034namespace transport
35{
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080036
William A. Kennington IIIc514d872019-04-06 18:19:38 -070037using phosphor::logging::commit;
38using phosphor::logging::elog;
39using phosphor::logging::entry;
40using phosphor::logging::level;
41using phosphor::logging::log;
42using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
43using sdbusplus::xyz::openbmc_project::Network::server::IP;
44
45// LAN Handler specific response codes
46constexpr Cc ccParamNotSupported = 0x80;
47constexpr Cc ccParamSetLocked = 0x81;
48constexpr Cc ccParamReadOnly = 0x82;
49
50// VLANs are a 12-bit value
51constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
52constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
53
54// D-Bus Network Daemon definitions
55constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
56constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config";
57
58constexpr auto INTF_SYSTEMCONFIG =
59 "xyz.openbmc_project.Network.SystemConfiguration";
60constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
61constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
62constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
63constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
64constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
65constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
66
67/** @brief Generic paramters for different address families */
68template <int family>
69struct AddrFamily
70{
71};
72
73/** @brief Parameter specialization for IPv4 */
74template <>
75struct AddrFamily<AF_INET>
76{
77 using addr = in_addr;
78 static constexpr auto protocol = IP::Protocol::IPv4;
79 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
80 static constexpr uint8_t defaultPrefix = 32;
81 static constexpr char propertyGateway[] = "DefaultGateway";
82};
83
84/** @brief Valid address origins for IPv4 */
85const std::unordered_set<IP::AddressOrigin> originsV4 = {
86 IP::AddressOrigin::Static,
87 IP::AddressOrigin::DHCP,
88};
89
90/** @brief Interface IP Address configuration parameters */
91template <int family>
92struct IfAddr
93{
94 std::string path;
95 typename AddrFamily<family>::addr address;
96 IP::AddressOrigin origin;
97 uint8_t prefix;
98};
99
100/** @brief IPMI LAN Parameters */
101enum class LanParam : uint8_t
102{
103 SetStatus = 0,
104 AuthSupport = 1,
105 AuthEnables = 2,
106 IP = 3,
107 IPSrc = 4,
108 MAC = 5,
109 SubnetMask = 6,
110 Gateway1 = 12,
111 VLANId = 20,
112 CiphersuiteSupport = 22,
113 CiphersuiteEntries = 23,
114};
115
116/** @brief IPMI IP Origin Types */
117enum class IPSrc : uint8_t
118{
119 Unspecified = 0,
120 Static = 1,
121 DHCP = 2,
122 BIOS = 3,
123 BMC = 4,
124};
125
126/** @brief IPMI Set Status */
127enum class SetStatus : uint8_t
128{
129 Complete = 0,
130 InProgress = 1,
131 Commit = 2,
132};
133
134/** @brief Copies bytes from an array into a trivially copyable container
135 *
136 * @params[out] t - The container receiving the data
137 * @params[in] bytes - The data to copy
138 */
139template <size_t N, typename T>
140void copyInto(T& t, const std::array<uint8_t, N>& bytes)
141{
142 static_assert(std::is_trivially_copyable_v<T>);
143 static_assert(N == sizeof(T));
144 std::memcpy(&t, bytes.data(), bytes.size());
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800145}
146
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700147/** @brief Gets a generic view of the bytes in the input container
148 *
149 * @params[in] t - The data to reference
150 * @return A string_view referencing the bytes in the container
151 */
152template <typename T>
153std::string_view dataRef(const T& t)
tomjose26e17732016-03-03 08:52:51 -0600154{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700155 static_assert(std::is_trivially_copyable_v<T>);
156 return {reinterpret_cast<const char*>(&t), sizeof(T)};
157}
Ratan Gupta533d03b2017-07-30 10:39:22 +0530158
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700159/** @brief The dbus parameters for the interface corresponding to a channel
160 * This helps reduce the number of mapper lookups we need for each
161 * query and simplifies finding the VLAN interface if needed.
162 */
163struct ChannelParams
164{
165 /** @brief The channel ID */
166 int id;
167 /** @brief channel name for the interface */
168 std::string ifname;
169 /** @brief Name of the service on the bus */
170 std::string service;
171 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
172 std::string ifPath;
173 /** @brief Logical adapter path used for address assignment */
174 std::string logicalPath;
175};
176
177/** @brief Determines the ethernet interface name corresponding to a channel
178 * Tries to map a VLAN object first so that the address information
179 * is accurate. Otherwise it gets the standard ethernet interface.
180 *
181 * @param[in] bus - The bus object used for lookups
182 * @param[in] channel - The channel id corresponding to an ethernet interface
183 * @return Ethernet interface service and object path if it exists
184 */
185std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
186 uint8_t channel)
187{
188 auto ifname = getChannelName(channel);
189 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800190 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700191 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800192 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800193
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700194 // Enumerate all VLAN + ETHERNET interfaces
195 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
196 "GetSubTree");
197 req.append(PATH_ROOT, 0,
198 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
199 auto reply = bus.call(req);
200 ObjectTree objs;
201 reply.read(objs);
202
203 ChannelParams params;
204 for (const auto& [path, impls] : objs)
205 {
206 if (path.find(ifname) == path.npos)
207 {
208 continue;
209 }
210 for (const auto& [service, intfs] : impls)
211 {
212 bool vlan = false;
213 bool ethernet = false;
214 for (const auto& intf : intfs)
215 {
216 if (intf == INTF_VLAN)
217 {
218 vlan = true;
219 }
220 else if (intf == INTF_ETHERNET)
221 {
222 ethernet = true;
223 }
224 }
225 if (params.service.empty() && (vlan || ethernet))
226 {
227 params.service = service;
228 }
229 if (params.ifPath.empty() && !vlan && ethernet)
230 {
231 params.ifPath = path;
232 }
233 if (params.logicalPath.empty() && vlan)
234 {
235 params.logicalPath = path;
236 }
237 }
238 }
239
240 // We must have a path for the underlying interface
241 if (params.ifPath.empty())
242 {
243 return std::nullopt;
244 }
245 // We don't have a VLAN so the logical path is the same
246 if (params.logicalPath.empty())
247 {
248 params.logicalPath = params.ifPath;
249 }
250
251 params.id = channel;
252 params.ifname = std::move(ifname);
253 return std::move(params);
254}
255
256/** @brief A trivial helper around maybeGetChannelParams() that throws an
257 * exception when it is unable to acquire parameters for the channel.
258 *
259 * @param[in] bus - The bus object used for lookups
260 * @param[in] channel - The channel id corresponding to an ethernet interface
261 * @return Ethernet interface service and object path
262 */
263ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
264{
265 auto params = maybeGetChannelParams(bus, channel);
266 if (!params)
267 {
268 log<level::ERR>("Failed to get channel params",
269 entry("CHANNEL=%" PRIu8, channel));
270 elog<InternalFailure>();
271 }
272 return std::move(*params);
273}
274
275/** @brief Wraps the phosphor logging method to insert some additional metadata
276 *
277 * @param[in] params - The parameters for the channel
278 * ...
279 */
280template <auto level, typename... Args>
281auto logWithChannel(const ChannelParams& params, Args&&... args)
282{
283 return log<level>(std::forward<Args>(args)...,
284 entry("CHANNEL=%d", params.id),
285 entry("IFNAME=%s", params.ifname.c_str()));
286}
287template <auto level, typename... Args>
288auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
289{
290 if (params)
291 {
292 return logWithChannel<level>(*params, std::forward<Args>(args)...);
293 }
294 return log<level>(std::forward<Args>(args)...);
295}
296
297/** @brief Trivializes using parameter getter functions by providing a bus
298 * and channel parameters automatically.
299 *
300 * @param[in] channel - The channel id corresponding to an ethernet interface
301 * ...
302 */
303template <auto func, typename... Args>
304auto channelCall(uint8_t channel, Args&&... args)
305{
306 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
307 auto params = getChannelParams(bus, channel);
308 return std::invoke(func, bus, params, std::forward<Args>(args)...);
309}
310
311/** @brief Determines if the ethernet interface is using DHCP
312 *
313 * @param[in] bus - The bus object used for lookups
314 * @param[in] params - The parameters for the channel
315 * @return True if DHCP is enabled, false otherwise
316 */
317bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
318{
319 return std::get<bool>(getDbusProperty(
320 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
321}
322
323/** @brief Sets the system value for DHCP on the given interface
324 *
325 * @param[in] bus - The bus object used for lookups
326 * @param[in] params - The parameters for the channel
327 * @param[in] on - Whether or not to enable DHCP
328 */
329void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
330 bool on)
331{
332 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
333 "DHCPEnabled", on);
334}
335
336/** @brief Converts a human readable MAC string into MAC bytes
337 *
338 * @param[in] mac - The MAC string
339 * @return MAC in bytes
340 */
341ether_addr stringToMAC(const char* mac)
342{
343 const ether_addr* ret = ether_aton(mac);
344 if (ret == nullptr)
345 {
346 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
347 elog<InternalFailure>();
348 }
349 return *ret;
350}
351
352/** @brief Determines the MAC of the ethernet interface
353 *
354 * @param[in] bus - The bus object used for lookups
355 * @param[in] params - The parameters for the channel
356 * @return The configured mac address
357 */
358ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
359{
360 auto macStr = std::get<std::string>(getDbusProperty(
361 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
362 return stringToMAC(macStr.c_str());
363}
364
365/** @brief Sets the system value for MAC address on the given interface
366 *
367 * @param[in] bus - The bus object used for lookups
368 * @param[in] params - The parameters for the channel
369 * @param[in] mac - MAC address to apply
370 */
371void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
372 const ether_addr& mac)
373{
374 std::string macStr = ether_ntoa(&mac);
375 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
376 macStr);
377}
378
379/** @brief Turns an IP address string into the network byte order form
380 * NOTE: This version strictly validates family matches
381 *
382 * @param[in] address - The string form of the address
383 * @return A network byte order address or none if conversion failed
384 */
385template <int family>
386std::optional<typename AddrFamily<family>::addr>
387 maybeStringToAddr(const char* address)
388{
389 typename AddrFamily<family>::addr ret;
390 if (inet_pton(family, address, &ret) == 1)
391 {
392 return ret;
393 }
394 return std::nullopt;
395}
396
397/** @brief Turns an IP address string into the network byte order form
398 * NOTE: This version strictly validates family matches
399 *
400 * @param[in] address - The string form of the address
401 * @return A network byte order address
402 */
403template <int family>
404typename AddrFamily<family>::addr stringToAddr(const char* address)
405{
406 auto ret = maybeStringToAddr<family>(address);
407 if (!ret)
408 {
409 log<level::ERR>("Failed to convert IP Address",
410 entry("FAMILY=%d", family),
411 entry("ADDRESS=%s", address));
412 elog<InternalFailure>();
413 }
414 return *ret;
415}
416
417/** @brief Turns an IP address in network byte order into a string
418 *
419 * @param[in] address - The string form of the address
420 * @return A network byte order address
421 */
422template <int family>
423std::string addrToString(const typename AddrFamily<family>::addr& address)
424{
425 std::string ret(AddrFamily<family>::maxStrLen, '\0');
426 inet_ntop(family, &address, ret.data(), ret.size());
427 ret.resize(strlen(ret.c_str()));
428 return ret;
429}
430
431/** @brief Retrieves the current gateway for the address family on the system
432 * NOTE: The gateway is currently system wide and not per channel
433 *
434 * @param[in] bus - The bus object used for lookups
435 * @param[in] params - The parameters for the channel
436 * @return An address representing the gateway address if it exists
437 */
438template <int family>
439std::optional<typename AddrFamily<family>::addr>
440 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
441{
442 auto gatewayStr = std::get<std::string>(getDbusProperty(
443 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
444 AddrFamily<family>::propertyGateway));
445 if (gatewayStr.empty())
446 {
447 return std::nullopt;
448 }
449 return stringToAddr<family>(gatewayStr.c_str());
450}
451
452/** @brief Sets the system wide value for the default gateway
453 *
454 * @param[in] bus - The bus object used for lookups
455 * @param[in] params - The parameters for the channel
456 * @param[in] gateway - Gateway address to apply
457 */
458template <int family>
459void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
460 const typename AddrFamily<family>::addr& address)
461{
462 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG,
463 AddrFamily<family>::propertyGateway,
464 addrToString<family>(address));
465}
466
467/** @brief A lazy lookup mechanism for iterating over object properties stored
468 * in DBus. This will only perform the object lookup when needed, and
469 * retains a cache of previous lookups to speed up future iterations.
470 */
471class ObjectLookupCache
472{
473 public:
474 using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
475
476 /** @brief Creates a new ObjectLookupCache for the interface on the bus
477 * NOTE: The inputs to this object must outlive the object since
478 * they are only referenced by it.
479 *
480 * @param[in] bus - The bus object used for lookups
481 * @param[in] params - The parameters for the channel
482 * @param[in] intf - The interface we are looking up
483 */
484 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
485 const char* intf) :
486 bus(bus),
487 params(params), intf(intf),
488 objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
489 {
490 }
491
492 class iterator : public ObjectTree::const_iterator
493 {
494 public:
495 using value_type = PropertiesCache::value_type;
496
497 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
498 ObjectTree::const_iterator(it), container(container),
499 ret(container.cache.end())
500 {
501 }
502 value_type& operator*()
503 {
504 ret = container.get(ObjectTree::const_iterator::operator*().first);
505 return *ret;
506 }
507 value_type* operator->()
508 {
509 return &operator*();
510 }
511
512 private:
513 ObjectLookupCache& container;
514 PropertiesCache::iterator ret;
515 };
516
517 iterator begin() noexcept
518 {
519 return iterator(objs.begin(), *this);
520 }
521
522 iterator end() noexcept
523 {
524 return iterator(objs.end(), *this);
525 }
526
527 private:
528 sdbusplus::bus::bus& bus;
529 const ChannelParams& params;
530 const char* const intf;
531 const ObjectTree objs;
532 PropertiesCache cache;
533
534 /** @brief Gets a cached copy of the object properties if possible
535 * Otherwise performs a query on DBus to look them up
536 *
537 * @param[in] path - The object path to lookup
538 * @return An iterator for the specified object path + properties
539 */
540 PropertiesCache::iterator get(const std::string& path)
541 {
542 auto it = cache.find(path);
543 if (it != cache.end())
544 {
545 return it;
546 }
547 auto properties = getAllDbusProperties(bus, params.service, path, intf);
548 return cache.insert({path, std::move(properties)}).first;
549 }
550};
551
552/** @brief Searches the ip object lookup cache for an address matching
553 * the input parameters. NOTE: The index lacks stability across address
554 * changes since the network daemon has no notion of stable indicies.
555 *
556 * @param[in] bus - The bus object used for lookups
557 * @param[in] params - The parameters for the channel
558 * @param[in] idx - The index of the desired address on the interface
559 * @param[in] origins - The allowed origins for the address objects
560 * @param[in] ips - The object lookup cache holding all of the address info
561 * @return The address and prefix if it was found
562 */
563template <int family>
564std::optional<IfAddr<family>>
565 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
566 uint8_t idx,
567 const std::unordered_set<IP::AddressOrigin>& origins,
568 ObjectLookupCache& ips)
569{
570 for (const auto& [path, properties] : ips)
571 {
572 const auto& addrStr = std::get<std::string>(properties.at("Address"));
573 auto addr = maybeStringToAddr<family>(addrStr.c_str());
574 if (!addr)
575 {
576 continue;
577 }
578
579 IP::AddressOrigin origin = IP::convertAddressOriginFromString(
580 std::get<std::string>(properties.at("Origin")));
581 if (origins.find(origin) == origins.end())
582 {
583 continue;
584 }
585
586 if (idx > 0)
587 {
588 idx--;
589 continue;
590 }
591
592 IfAddr<family> ifaddr;
593 ifaddr.path = path;
594 ifaddr.address = *addr;
595 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
596 ifaddr.origin = origin;
597 return std::move(ifaddr);
598 }
599
600 return std::nullopt;
601}
602
603/** @brief Trivial helper around findIfAddr that simplifies calls
604 * for one off lookups. Don't use this if you intend to do multiple
605 * lookups at a time.
606 *
607 * @param[in] bus - The bus object used for lookups
608 * @param[in] params - The parameters for the channel
609 * @param[in] idx - The index of the desired address on the interface
610 * @param[in] origins - The allowed origins for the address objects
611 * @return The address and prefix if it was found
612 */
613template <int family>
614auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
615 uint8_t idx,
616 const std::unordered_set<IP::AddressOrigin>& origins)
617{
618 ObjectLookupCache ips(bus, params, INTF_IP);
619 return findIfAddr<family>(bus, params, idx, origins, ips);
620}
621
622/** @brief Deletes the dbus object. Ignores empty objects or objects that are
623 * missing from the bus.
624 *
625 * @param[in] bus - The bus object used for lookups
626 * @param[in] service - The name of the service
627 * @param[in] path - The path of the object to delete
628 */
629void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
630 const std::string& path)
631{
632 if (path.empty())
633 {
634 return;
635 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530636 try
tomjose26e17732016-03-03 08:52:51 -0600637 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700638 auto req = bus.new_method_call(service.c_str(), path.c_str(),
639 ipmi::DELETE_INTERFACE, "Delete");
640 bus.call_noreply(req);
641 }
642 catch (const sdbusplus::exception::SdBusError& e)
643 {
644 if (strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600645 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700646 // We want to rethrow real errors
647 throw;
tomjose26e17732016-03-03 08:52:51 -0600648 }
649 }
tomjose26e17732016-03-03 08:52:51 -0600650}
651
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700652/** @brief Sets the address info configured for the interface
653 * If a previous address path exists then it will be removed
654 * before the new address is added.
655 *
656 * @param[in] bus - The bus object used for lookups
657 * @param[in] params - The parameters for the channel
658 * @param[in] address - The address of the new IP
659 * @param[in] prefix - The prefix of the new IP
660 */
661template <int family>
662void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
663 const typename AddrFamily<family>::addr& address,
664 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530665{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700666 auto newreq =
667 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
668 INTF_IP_CREATE, "IP");
669 std::string protocol =
670 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
671 AddrFamily<family>::protocol);
672 newreq.append(protocol, addrToString<family>(address), prefix, "");
673 bus.call_noreply(newreq);
674}
Tom Josepha30c8d32018-03-22 02:15:03 +0530675
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700676/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
677 *
678 * @param[in] bus - The bus object used for lookups
679 * @param[in] params - The parameters for the channel
680 * @return The address and prefix if found
681 */
682auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530683{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700684 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
685}
Tom Josepha30c8d32018-03-22 02:15:03 +0530686
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700687/** @brief Reconfigures the IPv4 address info configured for the interface
688 *
689 * @param[in] bus - The bus object used for lookups
690 * @param[in] params - The parameters for the channel
691 * @param[in] address - The new address if specified
692 * @param[in] prefix - The new address prefix if specified
693 */
694void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
695 const std::optional<in_addr>& address,
696 std::optional<uint8_t> prefix)
697{
698 auto ifaddr = getIfAddr4(bus, params);
699 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530700 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700701 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530702 elog<InternalFailure>();
703 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700704 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
705 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530706 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700707 fallbackPrefix = ifaddr->prefix;
708 deleteObjectIfExists(bus, params.service, ifaddr->path);
709 }
710 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
711 prefix.value_or(fallbackPrefix));
712}
713
714/** @brief Gets the vlan ID configured on the interface
715 *
716 * @param[in] bus - The bus object used for lookups
717 * @param[in] params - The parameters for the channel
718 * @return VLAN id or the standard 0 for no VLAN
719 */
720uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
721{
722 // VLAN devices will always have a separate logical object
723 if (params.ifPath == params.logicalPath)
724 {
725 return 0;
726 }
727
728 auto vlan = std::get<uint32_t>(getDbusProperty(
729 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
730 if ((vlan & VLAN_VALUE_MASK) != vlan)
731 {
732 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
733 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530734 elog<InternalFailure>();
735 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700736 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530737}
738
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700739/** @brief Deletes all of the possible configuration parameters for a channel
740 *
741 * @param[in] bus - The bus object used for lookups
742 * @param[in] params - The parameters for the channel
743 */
744void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500745{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700746 // Delete all objects associated with the interface
747 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
748 "GetSubTree");
749 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
750 auto objreply = bus.call(objreq);
751 ObjectTree objs;
752 objreply.read(objs);
753 for (const auto& [path, impls] : objs)
754 {
755 if (path.find(params.ifname) == path.npos)
756 {
757 continue;
758 }
759 for (const auto& [service, intfs] : impls)
760 {
761 deleteObjectIfExists(bus, service, path);
762 }
763 // Update params to reflect the deletion of vlan
764 if (path == params.logicalPath)
765 {
766 params.logicalPath = params.ifPath;
767 }
768 }
769
770 // Clear out any settings on the lower physical interface
771 setDHCPProperty(bus, params, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500772}
773
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700774/** @brief Creates a new VLAN on the specified interface
775 *
776 * @param[in] bus - The bus object used for lookups
777 * @param[in] params - The parameters for the channel
778 * @param[in] vlan - The id of the new vlan
779 */
780void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530781{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700782 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530783 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700784 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530785 }
786
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700787 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
788 INTF_VLAN_CREATE, "VLAN");
789 req.append(params.ifname, static_cast<uint32_t>(vlan));
790 auto reply = bus.call(req);
791 sdbusplus::message::object_path newPath;
792 reply.read(newPath);
793 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530794}
795
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700796/** @brief Performs the necessary reconfiguration to change the VLAN
797 *
798 * @param[in] bus - The bus object used for lookups
799 * @param[in] params - The parameters for the channel
800 * @param[in] vlan - The new vlan id to use
801 */
802void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
803 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500804{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700805 // Unfortunatetly we don't have built-in functions to migrate our interface
806 // customizations to new VLAN interfaces, or have some kind of decoupling.
807 // We therefore must retain all of our old information, setup the new VLAN
808 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800809
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700810 // Save info from the old logical interface
811 ObjectLookupCache ips(bus, params, INTF_IP);
812 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
813 auto dhcp = getDHCPProperty(bus, params);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500814
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700815 deconfigureChannel(bus, params);
816 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500817
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700818 // Re-establish the saved settings
819 setDHCPProperty(bus, params, dhcp);
820 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800821 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700822 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800823 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700824}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800825
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700826/** @brief Turns a prefix into a netmask
827 *
828 * @param[in] prefix - The prefix length
829 * @return The netmask
830 */
831in_addr prefixToNetmask(uint8_t prefix)
832{
833 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500834 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700835 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
836 elog<InternalFailure>();
837 }
838 if (prefix == 0)
839 {
840 // Avoids 32-bit lshift by 32 UB
841 return {};
842 }
843 return {htobe32(~UINT32_C(0) << (32 - prefix))};
844}
845
846/** @brief Turns a a netmask into a prefix length
847 *
848 * @param[in] netmask - The netmask in byte form
849 * @return The prefix length
850 */
851uint8_t netmaskToPrefix(in_addr netmask)
852{
853 uint32_t x = be32toh(netmask.s_addr);
854 if ((~x & (~x + 1)) != 0)
855 {
856 char maskStr[INET_ADDRSTRLEN];
857 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
858 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
859 elog<InternalFailure>();
860 }
861 return 32 - __builtin_ctz(x);
862}
863
864// We need to store this value so it can be returned to the client
865// It is volatile so safe to store in daemon memory.
866static std::unordered_map<uint8_t, SetStatus> setStatus;
867
868// Until we have good support for fixed versions of IPMI tool
869// we need to return the VLAN id for disabled VLANs. The value is only
870// used for verification that a disable operation succeeded and will only
871// be sent if our system indicates that vlans are disabled.
872static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
873
874/** @brief Gets the set status for the channel if it exists
875 * Otherise populates and returns the default value.
876 *
877 * @param[in] channel - The channel id corresponding to an ethernet interface
878 * @return A reference to the SetStatus for the channel
879 */
880SetStatus& getSetStatus(uint8_t channel)
881{
882 auto it = setStatus.find(channel);
883 if (it != setStatus.end())
884 {
885 return it->second;
886 }
887 return setStatus[channel] = SetStatus::Complete;
888}
889
890RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
891 message::Payload& req)
892{
893 auto channel = static_cast<uint8_t>(channelBits);
894 if (!doesDeviceExist(channel))
895 {
896 req.trailingOk = true;
897 return responseInvalidFieldRequest();
898 }
899
900 switch (static_cast<LanParam>(parameter))
901 {
902 case LanParam::SetStatus:
903 {
904 uint2_t flag;
905 uint6_t rsvd;
906 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
907 {
908 return responseReqDataLenInvalid();
909 }
910 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
911 switch (status)
912 {
913 case SetStatus::Complete:
914 {
915 getSetStatus(channel) = status;
916 return responseSuccess();
917 }
918 case SetStatus::InProgress:
919 {
920 auto& storedStatus = getSetStatus(channel);
921 if (storedStatus == SetStatus::InProgress)
922 {
923 return response(ccParamSetLocked);
924 }
925 storedStatus = status;
926 return responseSuccess();
927 }
928 case SetStatus::Commit:
929 if (getSetStatus(channel) != SetStatus::InProgress)
930 {
931 return responseInvalidFieldRequest();
932 }
933 return responseSuccess();
934 }
935 return response(ccParamNotSupported);
936 }
937 case LanParam::AuthSupport:
938 {
939 req.trailingOk = true;
940 return response(ccParamReadOnly);
941 }
942 case LanParam::AuthEnables:
943 {
944 req.trailingOk = true;
945 return response(ccParamNotSupported);
946 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800947 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600948 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700949 in_addr ip;
950 std::array<uint8_t, sizeof(ip)> bytes;
951 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
952 {
953 return responseReqDataLenInvalid();
954 }
955 copyInto(ip, bytes);
956 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
957 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530958 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700959 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530960 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700961 uint4_t flag;
962 uint4_t rsvd;
963 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
964 {
965 return responseReqDataLenInvalid();
966 }
967 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
968 {
969 case IPSrc::DHCP:
970 {
971 channelCall<setDHCPProperty>(channel, true);
972 return responseSuccess();
973 }
974 case IPSrc::Unspecified:
975 case IPSrc::Static:
976 case IPSrc::BIOS:
977 case IPSrc::BMC:
978 {
979 channelCall<setDHCPProperty>(channel, false);
980 return responseSuccess();
981 }
982 }
983 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530984 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800985 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530986 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700987 ether_addr mac;
988 std::array<uint8_t, sizeof(mac)> bytes;
989 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530990 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700991 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530992 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700993 copyInto(mac, bytes);
994 channelCall<setMACProperty>(channel, mac);
995 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530996 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700997 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530998 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700999 in_addr netmask;
1000 std::array<uint8_t, sizeof(netmask)> bytes;
1001 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301002 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001003 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301004 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001005 copyInto(netmask, bytes);
1006 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
1007 netmaskToPrefix(netmask));
1008 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301009 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001010 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301011 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001012 in_addr gateway;
1013 std::array<uint8_t, sizeof(gateway)> bytes;
1014 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1015 {
1016 return responseReqDataLenInvalid();
1017 }
1018 copyInto(gateway, bytes);
1019 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1020 return responseSuccess();
1021 }
1022 case LanParam::VLANId:
1023 {
1024 uint16_t vlanData;
1025 if (req.unpack(vlanData) != 0 || !req.fullyUnpacked())
1026 {
1027 return responseReqDataLenInvalid();
1028 }
1029 if ((vlanData & VLAN_ENABLE_FLAG) == 0)
1030 {
1031 lastDisabledVlan[channel] = vlanData & VLAN_VALUE_MASK;
1032 vlanData = 0;
1033 }
1034 channelCall<reconfigureVLAN>(channel, vlanData & VLAN_VALUE_MASK);
1035 return responseSuccess();
1036 }
1037 case LanParam::CiphersuiteSupport:
1038 case LanParam::CiphersuiteEntries:
1039 {
1040 req.trailingOk = true;
1041 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301042 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301043 }
vishwa1eaea4f2016-02-26 11:57:40 -06001044
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001045 req.trailingOk = true;
1046 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001047}
1048
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001049RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
1050 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301051{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001052 message::Payload ret;
1053 constexpr uint8_t current_revision = 0x11;
1054 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001055
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001056 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301057 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001058 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301059 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001060
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001061 auto channel = static_cast<uint8_t>(channelBits);
1062 if (!doesDeviceExist(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001063 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001064 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001065 }
1066
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001067 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301068 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001069 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301070 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001071 SetStatus status;
1072 try
1073 {
1074 status = setStatus.at(channel);
1075 }
1076 catch (const std::out_of_range&)
1077 {
1078 status = SetStatus::Complete;
1079 }
1080 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1081 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301082 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001083 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301084 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001085 std::bitset<6> support;
1086 ret.pack(support, uint2_t{});
1087 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301088 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001089 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001090 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001091 std::bitset<6> enables;
1092 ret.pack(enables, uint2_t{}); // Callback
1093 ret.pack(enables, uint2_t{}); // User
1094 ret.pack(enables, uint2_t{}); // Operator
1095 ret.pack(enables, uint2_t{}); // Admin
1096 ret.pack(enables, uint2_t{}); // OEM
1097 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001098 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001099 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001100 {
1101 auto ifaddr = channelCall<getIfAddr4>(channel);
1102 in_addr addr{};
1103 if (ifaddr)
1104 {
1105 addr = ifaddr->address;
1106 }
1107 ret.pack(dataRef(addr));
1108 return responseSuccess(std::move(ret));
1109 }
1110 case LanParam::IPSrc:
1111 {
1112 auto src = IPSrc::Static;
1113 if (channelCall<getDHCPProperty>(channel))
1114 {
1115 src = IPSrc::DHCP;
1116 }
1117 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1118 return responseSuccess(std::move(ret));
1119 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001120 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001121 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001122 ether_addr mac = channelCall<getMACProperty>(channel);
1123 ret.pack(dataRef(mac));
1124 return responseSuccess(std::move(ret));
1125 }
1126 case LanParam::SubnetMask:
1127 {
1128 auto ifaddr = channelCall<getIfAddr4>(channel);
1129 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1130 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301131 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001132 prefix = ifaddr->prefix;
1133 }
1134 in_addr netmask = prefixToNetmask(prefix);
1135 ret.pack(dataRef(netmask));
1136 return responseSuccess(std::move(ret));
1137 }
1138 case LanParam::Gateway1:
1139 {
1140 auto gateway =
1141 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1142 in_addr{});
1143 ret.pack(dataRef(gateway));
1144 return responseSuccess(std::move(ret));
1145 }
1146 case LanParam::VLANId:
1147 {
1148 uint16_t vlan = channelCall<getVLANProperty>(channel);
1149 if (vlan != 0)
1150 {
1151 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301152 }
1153 else
1154 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001155 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301156 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001157 ret.pack(vlan);
1158 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001159 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001160 case LanParam::CiphersuiteSupport:
1161 case LanParam::CiphersuiteEntries:
1162 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001163 }
1164
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001165 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001166}
1167
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001168} // namespace transport
1169} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301170
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001171void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301172
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001173void register_netfn_transport_functions()
1174{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001175 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1176 ipmi::transport::cmdSetLanConfigParameters,
1177 ipmi::Privilege::Admin, ipmi::transport::setLan);
1178 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1179 ipmi::transport::cmdGetLanConfigParameters,
1180 ipmi::Privilege::Admin, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001181}