1 #include "transporthandler.hpp"
2 
3 using phosphor::logging::commit;
4 using phosphor::logging::elog;
5 using phosphor::logging::entry;
6 using phosphor::logging::level;
7 using phosphor::logging::log;
8 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
9 using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
10 using sdbusplus::xyz::openbmc_project::Network::server::IP;
11 using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
12 
13 namespace cipher
14 {
15 
16 std::vector<uint8_t> getCipherList()
17 {
18     std::vector<uint8_t> cipherList;
19 
20     std::ifstream jsonFile(cipher::configFile);
21     if (!jsonFile.is_open())
22     {
23         log<level::ERR>("Channel Cipher suites file not found");
24         elog<InternalFailure>();
25     }
26 
27     auto data = Json::parse(jsonFile, nullptr, false);
28     if (data.is_discarded())
29     {
30         log<level::ERR>("Parsing channel cipher suites JSON failed");
31         elog<InternalFailure>();
32     }
33 
34     // Byte 1 is reserved
35     cipherList.push_back(0x00);
36 
37     for (const auto& record : data)
38     {
39         cipherList.push_back(record.value(cipher, 0));
40     }
41 
42     return cipherList;
43 }
44 } // namespace cipher
45 
46 namespace ipmi
47 {
48 namespace transport
49 {
50 
51 /** @brief Valid address origins for IPv4 */
52 const std::unordered_set<IP::AddressOrigin> originsV4 = {
53     IP::AddressOrigin::Static,
54     IP::AddressOrigin::DHCP,
55 };
56 
57 static constexpr uint8_t oemCmdStart = 192;
58 static constexpr uint8_t oemCmdEnd = 255;
59 
60 std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
61                                                    uint8_t channel)
62 {
63     auto ifname = getChannelName(channel);
64     if (ifname.empty())
65     {
66         return std::nullopt;
67     }
68 
69     // Enumerate all VLAN + ETHERNET interfaces
70     auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
71                                    "GetSubTree");
72     req.append(PATH_ROOT, 0,
73                std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
74     auto reply = bus.call(req);
75     ObjectTree objs;
76     reply.read(objs);
77 
78     ChannelParams params;
79     for (const auto& [path, impls] : objs)
80     {
81         if (path.find(ifname) == path.npos)
82         {
83             continue;
84         }
85         for (const auto& [service, intfs] : impls)
86         {
87             bool vlan = false;
88             bool ethernet = false;
89             for (const auto& intf : intfs)
90             {
91                 if (intf == INTF_VLAN)
92                 {
93                     vlan = true;
94                 }
95                 else if (intf == INTF_ETHERNET)
96                 {
97                     ethernet = true;
98                 }
99             }
100             if (params.service.empty() && (vlan || ethernet))
101             {
102                 params.service = service;
103             }
104             if (params.ifPath.empty() && !vlan && ethernet)
105             {
106                 params.ifPath = path;
107             }
108             if (params.logicalPath.empty() && vlan)
109             {
110                 params.logicalPath = path;
111             }
112         }
113     }
114 
115     // We must have a path for the underlying interface
116     if (params.ifPath.empty())
117     {
118         return std::nullopt;
119     }
120     // We don't have a VLAN so the logical path is the same
121     if (params.logicalPath.empty())
122     {
123         params.logicalPath = params.ifPath;
124     }
125 
126     params.id = channel;
127     params.ifname = std::move(ifname);
128     return std::move(params);
129 }
130 
131 ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
132 {
133     auto params = maybeGetChannelParams(bus, channel);
134     if (!params)
135     {
136         log<level::ERR>("Failed to get channel params",
137                         entry("CHANNEL=%" PRIu8, channel));
138         elog<InternalFailure>();
139     }
140     return std::move(*params);
141 }
142 
143 /** @brief Wraps the phosphor logging method to insert some additional metadata
144  *
145  *  @param[in] params - The parameters for the channel
146  *  ...
147  */
148 template <auto level, typename... Args>
149 auto logWithChannel(const ChannelParams& params, Args&&... args)
150 {
151     return log<level>(std::forward<Args>(args)...,
152                       entry("CHANNEL=%d", params.id),
153                       entry("IFNAME=%s", params.ifname.c_str()));
154 }
155 template <auto level, typename... Args>
156 auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
157 {
158     if (params)
159     {
160         return logWithChannel<level>(*params, std::forward<Args>(args)...);
161     }
162     return log<level>(std::forward<Args>(args)...);
163 }
164 
165 EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus::bus& bus,
166                                             const ChannelParams& params)
167 {
168     std::string dhcpstr = std::get<std::string>(getDbusProperty(
169         bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
170     return EthernetInterface::convertDHCPConfFromString(dhcpstr);
171 }
172 
173 /** @brief Sets the DHCP v4 state on the given interface
174  *
175  *  @param[in] bus           - The bus object used for lookups
176  *  @param[in] params        - The parameters for the channel
177  *  @param[in] requestedDhcp - DHCP state to assign
178  *                             (EthernetInterface::DHCPConf::none,
179  *                              EthernetInterface::DHCPConf::v4,
180  *                              EthernetInterface::DHCPConf::v6,
181  *                              EthernetInterface::DHCPConf::both)
182  */
183 void setDHCPv4Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
184                        const EthernetInterface::DHCPConf requestedDhcp)
185 {
186     EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
187     EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
188 
189     if ((currentDhcp == EthernetInterface::DHCPConf::v6) &&
190         (requestedDhcp == EthernetInterface::DHCPConf::v4))
191     {
192         nextDhcp = EthernetInterface::DHCPConf::both;
193     }
194     else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
195              (requestedDhcp == EthernetInterface::DHCPConf::v4))
196 
197     {
198         nextDhcp = requestedDhcp;
199     }
200     else if (requestedDhcp == EthernetInterface::DHCPConf::none)
201     {
202         if (currentDhcp == EthernetInterface::DHCPConf::both)
203         {
204             nextDhcp = EthernetInterface::DHCPConf::v6;
205         }
206         else if (currentDhcp == EthernetInterface::DHCPConf::v4)
207         {
208             nextDhcp = EthernetInterface::DHCPConf::none;
209         }
210     }
211     else
212     {
213         nextDhcp = currentDhcp;
214     }
215     std::string newDhcp =
216         sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
217             nextDhcp);
218     setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
219                     "DHCPEnabled", newDhcp);
220 }
221 
222 void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
223                        const EthernetInterface::DHCPConf requestedDhcp,
224                        const bool defaultMode = true)
225 {
226     EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
227     EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
228 
229     if (defaultMode)
230     {
231         if ((currentDhcp == EthernetInterface::DHCPConf::v4) &&
232             (requestedDhcp == EthernetInterface::DHCPConf::v6))
233         {
234             nextDhcp = EthernetInterface::DHCPConf::both;
235         }
236         else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
237                  (requestedDhcp == EthernetInterface::DHCPConf::v6))
238 
239         {
240             nextDhcp = requestedDhcp;
241         }
242         else if (requestedDhcp == EthernetInterface::DHCPConf::none)
243         {
244             if (currentDhcp == EthernetInterface::DHCPConf::both)
245             {
246                 nextDhcp = EthernetInterface::DHCPConf::v4;
247             }
248             else if (currentDhcp == EthernetInterface::DHCPConf::v6)
249             {
250                 nextDhcp = EthernetInterface::DHCPConf::none;
251             }
252         }
253         else
254         {
255             nextDhcp = currentDhcp;
256         }
257     }
258     else
259     {
260         // allow the v6 call to set any value
261         nextDhcp = requestedDhcp;
262     }
263 
264     std::string newDhcp =
265         sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
266             nextDhcp);
267     setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
268                     "DHCPEnabled", newDhcp);
269 }
270 
271 ether_addr stringToMAC(const char* mac)
272 {
273     const ether_addr* ret = ether_aton(mac);
274     if (ret == nullptr)
275     {
276         log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
277         elog<InternalFailure>();
278     }
279     return *ret;
280 }
281 
282 /** @brief Determines the MAC of the ethernet interface
283  *
284  *  @param[in] bus    - The bus object used for lookups
285  *  @param[in] params - The parameters for the channel
286  *  @return The configured mac address
287  */
288 ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
289 {
290     auto macStr = std::get<std::string>(getDbusProperty(
291         bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
292     return stringToMAC(macStr.c_str());
293 }
294 
295 /** @brief Sets the system value for MAC address on the given interface
296  *
297  *  @param[in] bus    - The bus object used for lookups
298  *  @param[in] params - The parameters for the channel
299  *  @param[in] mac    - MAC address to apply
300  */
301 void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
302                     const ether_addr& mac)
303 {
304     std::string macStr = ether_ntoa(&mac);
305     setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
306                     macStr);
307 }
308 
309 void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
310                           const std::string& path)
311 {
312     if (path.empty())
313     {
314         return;
315     }
316     try
317     {
318         auto req = bus.new_method_call(service.c_str(), path.c_str(),
319                                        ipmi::DELETE_INTERFACE, "Delete");
320         bus.call_noreply(req);
321     }
322     catch (const sdbusplus::exception::SdBusError& e)
323     {
324         if (strcmp(e.name(),
325                    "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
326             strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
327         {
328             // We want to rethrow real errors
329             throw;
330         }
331     }
332 }
333 
334 /** @brief Sets the address info configured for the interface
335  *         If a previous address path exists then it will be removed
336  *         before the new address is added.
337  *
338  *  @param[in] bus     - The bus object used for lookups
339  *  @param[in] params  - The parameters for the channel
340  *  @param[in] address - The address of the new IP
341  *  @param[in] prefix  - The prefix of the new IP
342  */
343 template <int family>
344 void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
345                   const typename AddrFamily<family>::addr& address,
346                   uint8_t prefix)
347 {
348     auto newreq =
349         bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
350                             INTF_IP_CREATE, "IP");
351     std::string protocol =
352         sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
353             AddrFamily<family>::protocol);
354     newreq.append(protocol, addrToString<family>(address), prefix, "");
355     bus.call_noreply(newreq);
356 }
357 
358 /** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
359  *
360  *  @param[in] bus    - The bus object used for lookups
361  *  @param[in] params - The parameters for the channel
362  *  @return The address and prefix if found
363  */
364 auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
365 {
366     return getIfAddr<AF_INET>(bus, params, 0, originsV4);
367 }
368 
369 /** @brief Reconfigures the IPv4 address info configured for the interface
370  *
371  *  @param[in] bus     - The bus object used for lookups
372  *  @param[in] params  - The parameters for the channel
373  *  @param[in] address - The new address if specified
374  *  @param[in] prefix  - The new address prefix if specified
375  */
376 void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
377                         const std::optional<in_addr>& address,
378                         std::optional<uint8_t> prefix)
379 {
380     auto ifaddr = getIfAddr4(bus, params);
381     if (!ifaddr && !address)
382     {
383         log<level::ERR>("Missing address for IPv4 assignment");
384         elog<InternalFailure>();
385     }
386     uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
387     if (ifaddr)
388     {
389         fallbackPrefix = ifaddr->prefix;
390         deleteObjectIfExists(bus, params.service, ifaddr->path);
391     }
392     createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
393                           prefix.value_or(fallbackPrefix));
394 }
395 
396 template <int family>
397 std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
398                                                    const ChannelParams& params,
399                                                    ObjectLookupCache& neighbors)
400 {
401     auto gateway = getGatewayProperty<family>(bus, params);
402     if (!gateway)
403     {
404         return std::nullopt;
405     }
406 
407     return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
408 }
409 
410 template <int family>
411 std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
412                                                   const ChannelParams& params)
413 {
414     ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
415     return findGatewayNeighbor<family>(bus, params, neighbors);
416 }
417 
418 template <int family>
419 void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
420                            const ChannelParams& params, const ether_addr& mac)
421 {
422     auto gateway = getGatewayProperty<family>(bus, params);
423     if (!gateway)
424     {
425         log<level::ERR>("Tried to set Gateway MAC without Gateway");
426         elog<InternalFailure>();
427     }
428 
429     ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
430     auto neighbor =
431         findStaticNeighbor<family>(bus, params, *gateway, neighbors);
432     if (neighbor)
433     {
434         deleteObjectIfExists(bus, params.service, neighbor->path);
435     }
436 
437     createNeighbor<family>(bus, params, *gateway, mac);
438 }
439 
440 /** @brief Deconfigures the IPv6 address info configured for the interface
441  *
442  *  @param[in] bus     - The bus object used for lookups
443  *  @param[in] params  - The parameters for the channel
444  *  @param[in] idx     - The address index to operate on
445  */
446 void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
447                         uint8_t idx)
448 {
449     auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
450     if (ifaddr)
451     {
452         deleteObjectIfExists(bus, params.service, ifaddr->path);
453     }
454 }
455 
456 /** @brief Reconfigures the IPv6 address info configured for the interface
457  *
458  *  @param[in] bus     - The bus object used for lookups
459  *  @param[in] params  - The parameters for the channel
460  *  @param[in] idx     - The address index to operate on
461  *  @param[in] address - The new address
462  *  @param[in] prefix  - The new address prefix
463  */
464 void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
465                         uint8_t idx, const in6_addr& address, uint8_t prefix)
466 {
467     deconfigureIfAddr6(bus, params, idx);
468     createIfAddr<AF_INET6>(bus, params, address, prefix);
469 }
470 
471 /** @brief Converts the AddressOrigin into an IPv6Source
472  *
473  *  @param[in] origin - The DBus Address Origin to convert
474  *  @return The IPv6Source version of the origin
475  */
476 IPv6Source originToSourceType(IP::AddressOrigin origin)
477 {
478     switch (origin)
479     {
480         case IP::AddressOrigin::Static:
481             return IPv6Source::Static;
482         case IP::AddressOrigin::DHCP:
483             return IPv6Source::DHCP;
484         case IP::AddressOrigin::SLAAC:
485             return IPv6Source::SLAAC;
486         default:
487         {
488             auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
489                 convertForMessage(origin);
490             log<level::ERR>(
491                 "Invalid IP::AddressOrigin conversion to IPv6Source",
492                 entry("ORIGIN=%s", originStr.c_str()));
493             elog<InternalFailure>();
494         }
495     }
496 }
497 
498 /** @brief Packs the IPMI message response with IPv6 address data
499  *
500  *  @param[out] ret     - The IPMI response payload to be packed
501  *  @param[in]  channel - The channel id corresponding to an ethernet interface
502  *  @param[in]  set     - The set selector for determining address index
503  *  @param[in]  origins - Set of valid origins for address filtering
504  */
505 void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
506                        const std::unordered_set<IP::AddressOrigin>& origins)
507 {
508     auto source = IPv6Source::Static;
509     bool enabled = false;
510     in6_addr addr{};
511     uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
512     auto status = IPv6AddressStatus::Disabled;
513 
514     auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
515     if (ifaddr)
516     {
517         source = originToSourceType(ifaddr->origin);
518         enabled = true;
519         addr = ifaddr->address;
520         prefix = ifaddr->prefix;
521         status = IPv6AddressStatus::Active;
522     }
523 
524     ret.pack(set);
525     ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
526     ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
527     ret.pack(prefix);
528     ret.pack(types::enum_cast<uint8_t>(status));
529 }
530 
531 /** @brief Gets the vlan ID configured on the interface
532  *
533  *  @param[in] bus    - The bus object used for lookups
534  *  @param[in] params - The parameters for the channel
535  *  @return VLAN id or the standard 0 for no VLAN
536  */
537 uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
538 {
539     // VLAN devices will always have a separate logical object
540     if (params.ifPath == params.logicalPath)
541     {
542         return 0;
543     }
544 
545     auto vlan = std::get<uint32_t>(getDbusProperty(
546         bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
547     if ((vlan & VLAN_VALUE_MASK) != vlan)
548     {
549         logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
550                                    entry("VLAN=%" PRIu32, vlan));
551         elog<InternalFailure>();
552     }
553     return vlan;
554 }
555 
556 /** @brief Deletes all of the possible configuration parameters for a channel
557  *
558  *  @param[in] bus    - The bus object used for lookups
559  *  @param[in] params - The parameters for the channel
560  */
561 void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
562 {
563     // Delete all objects associated with the interface
564     auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
565                                       "GetSubTree");
566     objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
567     auto objreply = bus.call(objreq);
568     ObjectTree objs;
569     objreply.read(objs);
570     for (const auto& [path, impls] : objs)
571     {
572         if (path.find(params.ifname) == path.npos)
573         {
574             continue;
575         }
576         for (const auto& [service, intfs] : impls)
577         {
578             deleteObjectIfExists(bus, service, path);
579         }
580         // Update params to reflect the deletion of vlan
581         if (path == params.logicalPath)
582         {
583             params.logicalPath = params.ifPath;
584         }
585     }
586 
587     // Clear out any settings on the lower physical interface
588     setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
589 }
590 
591 /** @brief Creates a new VLAN on the specified interface
592  *
593  *  @param[in] bus    - The bus object used for lookups
594  *  @param[in] params - The parameters for the channel
595  *  @param[in] vlan   - The id of the new vlan
596  */
597 void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
598 {
599     if (vlan == 0)
600     {
601         return;
602     }
603 
604     auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
605                                    INTF_VLAN_CREATE, "VLAN");
606     req.append(params.ifname, static_cast<uint32_t>(vlan));
607     auto reply = bus.call(req);
608     sdbusplus::message::object_path newPath;
609     reply.read(newPath);
610     params.logicalPath = std::move(newPath);
611 }
612 
613 /** @brief Performs the necessary reconfiguration to change the VLAN
614  *
615  *  @param[in] bus    - The bus object used for lookups
616  *  @param[in] params - The parameters for the channel
617  *  @param[in] vlan   - The new vlan id to use
618  */
619 void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
620                      uint16_t vlan)
621 {
622     // Unfortunatetly we don't have built-in functions to migrate our interface
623     // customizations to new VLAN interfaces, or have some kind of decoupling.
624     // We therefore must retain all of our old information, setup the new VLAN
625     // configuration, then restore the old info.
626 
627     // Save info from the old logical interface
628     ObjectLookupCache ips(bus, params, INTF_IP);
629     auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
630     std::vector<IfAddr<AF_INET6>> ifaddrs6;
631     for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
632     {
633         auto ifaddr6 =
634             findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
635         if (!ifaddr6)
636         {
637             break;
638         }
639         ifaddrs6.push_back(std::move(*ifaddr6));
640     }
641     EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
642     ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
643     auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
644     auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
645 
646     deconfigureChannel(bus, params);
647     createVLAN(bus, params, vlan);
648 
649     // Re-establish the saved settings
650     setDHCPv6Property(bus, params, dhcp, false);
651     if (ifaddr4)
652     {
653         createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
654     }
655     for (const auto& ifaddr6 : ifaddrs6)
656     {
657         createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
658     }
659     if (neighbor4)
660     {
661         createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
662     }
663     if (neighbor6)
664     {
665         createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
666     }
667 }
668 
669 /** @brief Turns a prefix into a netmask
670  *
671  *  @param[in] prefix - The prefix length
672  *  @return The netmask
673  */
674 in_addr prefixToNetmask(uint8_t prefix)
675 {
676     if (prefix > 32)
677     {
678         log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
679         elog<InternalFailure>();
680     }
681     if (prefix == 0)
682     {
683         // Avoids 32-bit lshift by 32 UB
684         return {};
685     }
686     return {htobe32(~UINT32_C(0) << (32 - prefix))};
687 }
688 
689 /** @brief Turns a a netmask into a prefix length
690  *
691  *  @param[in] netmask - The netmask in byte form
692  *  @return The prefix length
693  */
694 uint8_t netmaskToPrefix(in_addr netmask)
695 {
696     uint32_t x = be32toh(netmask.s_addr);
697     if ((~x & (~x + 1)) != 0)
698     {
699         char maskStr[INET_ADDRSTRLEN];
700         inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
701         log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
702         elog<InternalFailure>();
703     }
704     return static_cast<bool>(x)
705                ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
706                : 0;
707 }
708 
709 // We need to store this value so it can be returned to the client
710 // It is volatile so safe to store in daemon memory.
711 static std::unordered_map<uint8_t, SetStatus> setStatus;
712 
713 // Until we have good support for fixed versions of IPMI tool
714 // we need to return the VLAN id for disabled VLANs. The value is only
715 // used for verification that a disable operation succeeded and will only
716 // be sent if our system indicates that vlans are disabled.
717 static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
718 
719 /** @brief Gets the set status for the channel if it exists
720  *         Otherise populates and returns the default value.
721  *
722  *  @param[in] channel - The channel id corresponding to an ethernet interface
723  *  @return A reference to the SetStatus for the channel
724  */
725 SetStatus& getSetStatus(uint8_t channel)
726 {
727     auto it = setStatus.find(channel);
728     if (it != setStatus.end())
729     {
730         return it->second;
731     }
732     return setStatus[channel] = SetStatus::Complete;
733 }
734 
735 /** @brief Gets the IPv6 Router Advertisement value
736  *
737  *  @param[in] bus    - The bus object used for lookups
738  *  @param[in] params - The parameters for the channel
739  *  @return networkd IPV6AcceptRA value
740  */
741 static bool getIPv6AcceptRA(sdbusplus::bus::bus& bus,
742                             const ChannelParams& params)
743 {
744     auto raEnabled =
745         std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
746                                        INTF_ETHERNET, "IPv6AcceptRA"));
747     return raEnabled;
748 }
749 
750 /** @brief Sets the IPv6AcceptRA flag
751  *
752  *  @param[in] bus           - The bus object used for lookups
753  *  @param[in] params        - The parameters for the channel
754  *  @param[in] ipv6AcceptRA  - boolean to enable/disable IPv6 Routing
755  *                             Advertisement
756  */
757 void setIPv6AcceptRA(sdbusplus::bus::bus& bus, const ChannelParams& params,
758                      const bool ipv6AcceptRA)
759 {
760     setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
761                     "IPv6AcceptRA", ipv6AcceptRA);
762 }
763 
764 /**
765  * Define placeholder command handlers for the OEM Extension bytes for the Set
766  * LAN Configuration Parameters and Get LAN Configuration Parameters
767  * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
768  * functions below to be overridden.
769  * To create handlers for your own proprietary command set:
770  *   Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
771  *   recipe
772  *   Create C++ file(s) that define IPMI handler functions matching the
773  *     function names below (i.e. setLanOem). The default name for the
774  *     transport IPMI commands is transporthandler_oem.cpp.
775  *   Add:
776  *      EXTRA_OECONF_append = " --enable-transport-oem=yes"
777  *   Create a do_compile_prepend()/do_install_append method in your
778  *   bbappend file to copy the file to the build directory.
779  *   Add:
780  *   PROJECT_SRC_DIR := "${THISDIR}/${PN}"
781  *   # Copy the "strong" functions into the working directory, overriding the
782  *   # placeholder functions.
783  *   do_compile_prepend(){
784  *      cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
785  *   }
786  *
787  *   # Clean up after complilation has completed
788  *   do_install_append(){
789  *      rm -f ${S}/transporthandler_oem.cpp
790  *   }
791  *
792  */
793 
794 /**
795  * Define the placeholder OEM commands as having weak linkage. Create
796  * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
797  * file. The functions defined there must not have the "weak" attribute
798  * applied to them.
799  */
800 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
801     __attribute__((weak));
802 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
803                                     uint8_t set, uint8_t block)
804     __attribute__((weak));
805 
806 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
807 {
808     req.trailingOk = true;
809     return response(ccParamNotSupported);
810 }
811 
812 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
813                                     uint8_t set, uint8_t block)
814 {
815     return response(ccParamNotSupported);
816 }
817 /**
818  * @brief is MAC address valid.
819  *
820  * This function checks whether the MAC address is valid or not.
821  *
822  * @param[in] mac - MAC address.
823  * @return true if MAC address is valid else retun false.
824  **/
825 bool isValidMACAddress(const ether_addr& mac)
826 {
827     // check if mac address is empty
828     if (equal(mac, ether_addr{}))
829     {
830         return false;
831     }
832     // we accept only unicast MAC addresses and  same thing has been checked in
833     // phosphor-network layer. If the least significant bit of the first octet
834     // is set to 1, it is multicast MAC else it is unicast MAC address.
835     if (mac.ether_addr_octet[0] & 1)
836     {
837         return false;
838     }
839     return true;
840 }
841 
842 RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
843                  uint8_t parameter, message::Payload& req)
844 {
845     const uint8_t channel = convertCurrentChannelNum(
846         static_cast<uint8_t>(channelBits), ctx->channel);
847     if (reserved1 || !isValidChannel(channel))
848     {
849         log<level::ERR>("Set Lan - Invalid field in request");
850         req.trailingOk = true;
851         return responseInvalidFieldRequest();
852     }
853 
854     switch (static_cast<LanParam>(parameter))
855     {
856         case LanParam::SetStatus:
857         {
858             uint2_t flag;
859             uint6_t rsvd;
860             if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
861             {
862                 return responseReqDataLenInvalid();
863             }
864             if (rsvd)
865             {
866                 return responseInvalidFieldRequest();
867             }
868             auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
869             switch (status)
870             {
871                 case SetStatus::Complete:
872                 {
873                     getSetStatus(channel) = status;
874                     return responseSuccess();
875                 }
876                 case SetStatus::InProgress:
877                 {
878                     auto& storedStatus = getSetStatus(channel);
879                     if (storedStatus == SetStatus::InProgress)
880                     {
881                         return response(ccParamSetLocked);
882                     }
883                     storedStatus = status;
884                     return responseSuccess();
885                 }
886                 case SetStatus::Commit:
887                     if (getSetStatus(channel) != SetStatus::InProgress)
888                     {
889                         return responseInvalidFieldRequest();
890                     }
891                     return responseSuccess();
892             }
893             return response(ccParamNotSupported);
894         }
895         case LanParam::AuthSupport:
896         {
897             req.trailingOk = true;
898             return response(ccParamReadOnly);
899         }
900         case LanParam::AuthEnables:
901         {
902             req.trailingOk = true;
903             return response(ccParamReadOnly);
904         }
905         case LanParam::IP:
906         {
907             EthernetInterface::DHCPConf dhcp =
908                 channelCall<getDHCPProperty>(channel);
909             if ((dhcp == EthernetInterface::DHCPConf::v4) ||
910                 (dhcp == EthernetInterface::DHCPConf::both))
911             {
912                 return responseCommandNotAvailable();
913             }
914             in_addr ip;
915             std::array<uint8_t, sizeof(ip)> bytes;
916             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
917             {
918                 return responseReqDataLenInvalid();
919             }
920             copyInto(ip, bytes);
921             channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
922             return responseSuccess();
923         }
924         case LanParam::IPSrc:
925         {
926             uint4_t flag;
927             uint4_t rsvd;
928             if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
929             {
930                 return responseReqDataLenInvalid();
931             }
932             if (rsvd)
933             {
934                 return responseInvalidFieldRequest();
935             }
936             switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
937             {
938                 case IPSrc::DHCP:
939                 {
940                     // The IPSrc IPMI command is only for IPv4
941                     // management. Modifying IPv6 state is done using
942                     // a completely different Set LAN Configuration
943                     // subcommand.
944                     channelCall<setDHCPv4Property>(
945                         channel, EthernetInterface::DHCPConf::v4);
946                     return responseSuccess();
947                 }
948                 case IPSrc::Unspecified:
949                 case IPSrc::Static:
950                 {
951                     channelCall<setDHCPv4Property>(
952                         channel, EthernetInterface::DHCPConf::none);
953                     return responseSuccess();
954                 }
955                 case IPSrc::BIOS:
956                 case IPSrc::BMC:
957                 {
958                     return responseInvalidFieldRequest();
959                 }
960             }
961             return response(ccParamNotSupported);
962         }
963         case LanParam::MAC:
964         {
965             ether_addr mac;
966             std::array<uint8_t, sizeof(mac)> bytes;
967             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
968             {
969                 return responseReqDataLenInvalid();
970             }
971             copyInto(mac, bytes);
972 
973             if (!isValidMACAddress(mac))
974             {
975                 return responseInvalidFieldRequest();
976             }
977             channelCall<setMACProperty>(channel, mac);
978             return responseSuccess();
979         }
980         case LanParam::SubnetMask:
981         {
982             EthernetInterface::DHCPConf dhcp =
983                 channelCall<getDHCPProperty>(channel);
984             if ((dhcp == EthernetInterface::DHCPConf::v4) ||
985                 (dhcp == EthernetInterface::DHCPConf::both))
986             {
987                 return responseCommandNotAvailable();
988             }
989             in_addr netmask;
990             std::array<uint8_t, sizeof(netmask)> bytes;
991             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
992             {
993                 return responseReqDataLenInvalid();
994             }
995             copyInto(netmask, bytes);
996             channelCall<reconfigureIfAddr4>(channel, std::nullopt,
997                                             netmaskToPrefix(netmask));
998             return responseSuccess();
999         }
1000         case LanParam::Gateway1:
1001         {
1002             EthernetInterface::DHCPConf dhcp =
1003                 channelCall<getDHCPProperty>(channel);
1004             if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1005                 (dhcp == EthernetInterface::DHCPConf::both))
1006             {
1007                 return responseCommandNotAvailable();
1008             }
1009             in_addr gateway;
1010             std::array<uint8_t, sizeof(gateway)> bytes;
1011             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1012             {
1013                 return responseReqDataLenInvalid();
1014             }
1015             copyInto(gateway, bytes);
1016             channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1017             return responseSuccess();
1018         }
1019         case LanParam::Gateway1MAC:
1020         {
1021             ether_addr gatewayMAC;
1022             std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1023             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1024             {
1025                 return responseReqDataLenInvalid();
1026             }
1027             copyInto(gatewayMAC, bytes);
1028             channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1029             return responseSuccess();
1030         }
1031         case LanParam::VLANId:
1032         {
1033             uint12_t vlanData = 0;
1034             uint3_t reserved = 0;
1035             bool vlanEnable = 0;
1036 
1037             if (req.unpack(vlanData) || req.unpack(reserved) ||
1038                 req.unpack(vlanEnable) || !req.fullyUnpacked())
1039             {
1040                 return responseReqDataLenInvalid();
1041             }
1042 
1043             if (reserved)
1044             {
1045                 return responseInvalidFieldRequest();
1046             }
1047 
1048             uint16_t vlan = static_cast<uint16_t>(vlanData);
1049 
1050             if (!vlanEnable)
1051             {
1052                 lastDisabledVlan[channel] = vlan;
1053                 vlan = 0;
1054             }
1055             else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1056             {
1057                 return responseInvalidFieldRequest();
1058             }
1059 
1060             channelCall<reconfigureVLAN>(channel, vlan);
1061             return responseSuccess();
1062         }
1063         case LanParam::CiphersuiteSupport:
1064         case LanParam::CiphersuiteEntries:
1065         case LanParam::IPFamilySupport:
1066         {
1067             req.trailingOk = true;
1068             return response(ccParamReadOnly);
1069         }
1070         case LanParam::IPFamilyEnables:
1071         {
1072             uint8_t enables;
1073             if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1074             {
1075                 return responseReqDataLenInvalid();
1076             }
1077             switch (static_cast<IPFamilyEnables>(enables))
1078             {
1079                 case IPFamilyEnables::DualStack:
1080                     return responseSuccess();
1081                 case IPFamilyEnables::IPv4Only:
1082                 case IPFamilyEnables::IPv6Only:
1083                     return response(ccParamNotSupported);
1084             }
1085             return response(ccParamNotSupported);
1086         }
1087         case LanParam::IPv6Status:
1088         {
1089             req.trailingOk = true;
1090             return response(ccParamReadOnly);
1091         }
1092         case LanParam::IPv6StaticAddresses:
1093         {
1094             uint8_t set;
1095             uint7_t rsvd;
1096             bool enabled;
1097             in6_addr ip;
1098             std::array<uint8_t, sizeof(ip)> ipbytes;
1099             uint8_t prefix;
1100             uint8_t status;
1101             if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1102                 !req.fullyUnpacked())
1103             {
1104                 return responseReqDataLenInvalid();
1105             }
1106             if (rsvd)
1107             {
1108                 return responseInvalidFieldRequest();
1109             }
1110             copyInto(ip, ipbytes);
1111             if (enabled)
1112             {
1113                 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1114             }
1115             else
1116             {
1117                 channelCall<deconfigureIfAddr6>(channel, set);
1118             }
1119             return responseSuccess();
1120         }
1121         case LanParam::IPv6DynamicAddresses:
1122         {
1123             req.trailingOk = true;
1124             return response(ccParamReadOnly);
1125         }
1126         case LanParam::IPv6RouterControl:
1127         {
1128             std::bitset<8> control;
1129             constexpr uint8_t reservedRACCBits = 0xfc;
1130             if (req.unpack(control) != 0 || !req.fullyUnpacked())
1131             {
1132                 return responseReqDataLenInvalid();
1133             }
1134             if (std::bitset<8> expected(control &
1135                                         std::bitset<8>(reservedRACCBits));
1136                 expected.any())
1137             {
1138                 return response(ccParamNotSupported);
1139             }
1140 
1141             bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1142             channelCall<setIPv6AcceptRA>(channel, enableRA);
1143             return responseSuccess();
1144         }
1145         case LanParam::IPv6StaticRouter1IP:
1146         {
1147             in6_addr gateway;
1148             std::array<uint8_t, sizeof(gateway)> bytes;
1149             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1150             {
1151                 return responseReqDataLenInvalid();
1152             }
1153             copyInto(gateway, bytes);
1154             channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1155             return responseSuccess();
1156         }
1157         case LanParam::IPv6StaticRouter1MAC:
1158         {
1159             ether_addr mac;
1160             std::array<uint8_t, sizeof(mac)> bytes;
1161             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1162             {
1163                 return responseReqDataLenInvalid();
1164             }
1165             copyInto(mac, bytes);
1166             channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1167             return responseSuccess();
1168         }
1169         case LanParam::IPv6StaticRouter1PrefixLength:
1170         {
1171             uint8_t prefix;
1172             if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1173             {
1174                 return responseReqDataLenInvalid();
1175             }
1176             if (prefix != 0)
1177             {
1178                 return responseInvalidFieldRequest();
1179             }
1180             return responseSuccess();
1181         }
1182         case LanParam::IPv6StaticRouter1PrefixValue:
1183         {
1184             std::array<uint8_t, sizeof(in6_addr)> bytes;
1185             if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1186             {
1187                 return responseReqDataLenInvalid();
1188             }
1189             // Accept any prefix value since our prefix length has to be 0
1190             return responseSuccess();
1191         }
1192         case LanParam::cipherSuitePrivilegeLevels:
1193         {
1194             uint8_t reserved;
1195             std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1196 
1197             if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1198             {
1199                 return responseReqDataLenInvalid();
1200             }
1201 
1202             if (reserved)
1203             {
1204                 return responseInvalidFieldRequest();
1205             }
1206 
1207             uint8_t resp =
1208                 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1209                     .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1210             if (!resp)
1211             {
1212                 return responseSuccess();
1213             }
1214             else
1215             {
1216                 req.trailingOk = true;
1217                 return response(resp);
1218             }
1219         }
1220     }
1221 
1222     if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1223     {
1224         return setLanOem(channel, parameter, req);
1225     }
1226 
1227     req.trailingOk = true;
1228     return response(ccParamNotSupported);
1229 }
1230 
1231 RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1232                                  uint3_t reserved, bool revOnly,
1233                                  uint8_t parameter, uint8_t set, uint8_t block)
1234 {
1235     message::Payload ret;
1236     constexpr uint8_t current_revision = 0x11;
1237     ret.pack(current_revision);
1238 
1239     if (revOnly)
1240     {
1241         return responseSuccess(std::move(ret));
1242     }
1243 
1244     const uint8_t channel = convertCurrentChannelNum(
1245         static_cast<uint8_t>(channelBits), ctx->channel);
1246     if (reserved || !isValidChannel(channel))
1247     {
1248         log<level::ERR>("Get Lan - Invalid field in request");
1249         return responseInvalidFieldRequest();
1250     }
1251 
1252     static std::vector<uint8_t> cipherList;
1253     static bool listInit = false;
1254     if (!listInit)
1255     {
1256         try
1257         {
1258             cipherList = cipher::getCipherList();
1259             listInit = true;
1260         }
1261         catch (const std::exception& e)
1262         {
1263         }
1264     }
1265 
1266     switch (static_cast<LanParam>(parameter))
1267     {
1268         case LanParam::SetStatus:
1269         {
1270             SetStatus status;
1271             try
1272             {
1273                 status = setStatus.at(channel);
1274             }
1275             catch (const std::out_of_range&)
1276             {
1277                 status = SetStatus::Complete;
1278             }
1279             ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
1280             return responseSuccess(std::move(ret));
1281         }
1282         case LanParam::AuthSupport:
1283         {
1284             std::bitset<6> support;
1285             ret.pack(support, uint2_t{});
1286             return responseSuccess(std::move(ret));
1287         }
1288         case LanParam::AuthEnables:
1289         {
1290             std::bitset<6> enables;
1291             ret.pack(enables, uint2_t{}); // Callback
1292             ret.pack(enables, uint2_t{}); // User
1293             ret.pack(enables, uint2_t{}); // Operator
1294             ret.pack(enables, uint2_t{}); // Admin
1295             ret.pack(enables, uint2_t{}); // OEM
1296             return responseSuccess(std::move(ret));
1297         }
1298         case LanParam::IP:
1299         {
1300             auto ifaddr = channelCall<getIfAddr4>(channel);
1301             in_addr addr{};
1302             if (ifaddr)
1303             {
1304                 addr = ifaddr->address;
1305             }
1306             ret.pack(dataRef(addr));
1307             return responseSuccess(std::move(ret));
1308         }
1309         case LanParam::IPSrc:
1310         {
1311             auto src = IPSrc::Static;
1312             EthernetInterface::DHCPConf dhcp =
1313                 channelCall<getDHCPProperty>(channel);
1314             if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1315                 (dhcp == EthernetInterface::DHCPConf::both))
1316             {
1317                 src = IPSrc::DHCP;
1318             }
1319             ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
1320             return responseSuccess(std::move(ret));
1321         }
1322         case LanParam::MAC:
1323         {
1324             ether_addr mac = channelCall<getMACProperty>(channel);
1325             ret.pack(dataRef(mac));
1326             return responseSuccess(std::move(ret));
1327         }
1328         case LanParam::SubnetMask:
1329         {
1330             auto ifaddr = channelCall<getIfAddr4>(channel);
1331             uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1332             if (ifaddr)
1333             {
1334                 prefix = ifaddr->prefix;
1335             }
1336             in_addr netmask = prefixToNetmask(prefix);
1337             ret.pack(dataRef(netmask));
1338             return responseSuccess(std::move(ret));
1339         }
1340         case LanParam::Gateway1:
1341         {
1342             auto gateway =
1343                 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1344                     in_addr{});
1345             ret.pack(dataRef(gateway));
1346             return responseSuccess(std::move(ret));
1347         }
1348         case LanParam::Gateway1MAC:
1349         {
1350             ether_addr mac{};
1351             auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1352             if (neighbor)
1353             {
1354                 mac = neighbor->mac;
1355             }
1356             ret.pack(dataRef(mac));
1357             return responseSuccess(std::move(ret));
1358         }
1359         case LanParam::VLANId:
1360         {
1361             uint16_t vlan = channelCall<getVLANProperty>(channel);
1362             if (vlan != 0)
1363             {
1364                 vlan |= VLAN_ENABLE_FLAG;
1365             }
1366             else
1367             {
1368                 vlan = lastDisabledVlan[channel];
1369             }
1370             ret.pack(vlan);
1371             return responseSuccess(std::move(ret));
1372         }
1373         case LanParam::CiphersuiteSupport:
1374         {
1375             if (getChannelSessionSupport(channel) ==
1376                 EChannelSessSupported::none)
1377             {
1378                 return responseInvalidFieldRequest();
1379             }
1380             if (!listInit)
1381             {
1382                 return responseUnspecifiedError();
1383             }
1384             ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1385             return responseSuccess(std::move(ret));
1386         }
1387         case LanParam::CiphersuiteEntries:
1388         {
1389             if (getChannelSessionSupport(channel) ==
1390                 EChannelSessSupported::none)
1391             {
1392                 return responseInvalidFieldRequest();
1393             }
1394             if (!listInit)
1395             {
1396                 return responseUnspecifiedError();
1397             }
1398             ret.pack(cipherList);
1399             return responseSuccess(std::move(ret));
1400         }
1401         case LanParam::IPFamilySupport:
1402         {
1403             std::bitset<8> support;
1404             support[IPFamilySupportFlag::IPv6Only] = 0;
1405             support[IPFamilySupportFlag::DualStack] = 1;
1406             support[IPFamilySupportFlag::IPv6Alerts] = 1;
1407             ret.pack(support);
1408             return responseSuccess(std::move(ret));
1409         }
1410         case LanParam::IPFamilyEnables:
1411         {
1412             ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1413             return responseSuccess(std::move(ret));
1414         }
1415         case LanParam::IPv6Status:
1416         {
1417             ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1418             ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1419             std::bitset<8> support;
1420             support[IPv6StatusFlag::DHCP] = 1;
1421             support[IPv6StatusFlag::SLAAC] = 1;
1422             ret.pack(support);
1423             return responseSuccess(std::move(ret));
1424         }
1425         case LanParam::IPv6StaticAddresses:
1426         {
1427             if (set >= MAX_IPV6_STATIC_ADDRESSES)
1428             {
1429                 return responseParmOutOfRange();
1430             }
1431             getLanIPv6Address(ret, channel, set, originsV6Static);
1432             return responseSuccess(std::move(ret));
1433         }
1434         case LanParam::IPv6DynamicAddresses:
1435         {
1436             if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1437             {
1438                 return responseParmOutOfRange();
1439             }
1440             getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1441             return responseSuccess(std::move(ret));
1442         }
1443         case LanParam::IPv6RouterControl:
1444         {
1445             std::bitset<8> control;
1446             control[IPv6RouterControlFlag::Dynamic] =
1447                 channelCall<getIPv6AcceptRA>(channel);
1448             control[IPv6RouterControlFlag::Static] = 1;
1449             ret.pack(control);
1450             return responseSuccess(std::move(ret));
1451         }
1452         case LanParam::IPv6StaticRouter1IP:
1453         {
1454             in6_addr gateway{};
1455             EthernetInterface::DHCPConf dhcp =
1456                 channelCall<getDHCPProperty>(channel);
1457             if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1458                 (dhcp == EthernetInterface::DHCPConf::none))
1459             {
1460                 gateway =
1461                     channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1462                         in6_addr{});
1463             }
1464             ret.pack(dataRef(gateway));
1465             return responseSuccess(std::move(ret));
1466         }
1467         case LanParam::IPv6StaticRouter1MAC:
1468         {
1469             ether_addr mac{};
1470             auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1471             if (neighbor)
1472             {
1473                 mac = neighbor->mac;
1474             }
1475             ret.pack(dataRef(mac));
1476             return responseSuccess(std::move(ret));
1477         }
1478         case LanParam::IPv6StaticRouter1PrefixLength:
1479         {
1480             ret.pack(UINT8_C(0));
1481             return responseSuccess(std::move(ret));
1482         }
1483         case LanParam::IPv6StaticRouter1PrefixValue:
1484         {
1485             in6_addr prefix{};
1486             ret.pack(dataRef(prefix));
1487             return responseSuccess(std::move(ret));
1488         }
1489         case LanParam::cipherSuitePrivilegeLevels:
1490         {
1491             std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1492 
1493             uint8_t resp =
1494                 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1495                     .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1496             if (!resp)
1497             {
1498                 constexpr uint8_t reserved1 = 0x00;
1499                 ret.pack(reserved1, csPrivilegeLevels);
1500                 return responseSuccess(std::move(ret));
1501             }
1502             else
1503             {
1504                 return response(resp);
1505             }
1506         }
1507     }
1508 
1509     if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1510     {
1511         return getLanOem(channel, parameter, set, block);
1512     }
1513 
1514     return response(ccParamNotSupported);
1515 }
1516 
1517 } // namespace transport
1518 } // namespace ipmi
1519 
1520 void register_netfn_transport_functions() __attribute__((constructor));
1521 
1522 void register_netfn_transport_functions()
1523 {
1524     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1525                           ipmi::transport::cmdSetLanConfigParameters,
1526                           ipmi::Privilege::Admin, ipmi::transport::setLan);
1527     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1528                           ipmi::transport::cmdGetLanConfigParameters,
1529                           ipmi::Privilege::Operator, ipmi::transport::getLan);
1530 }
1531