blob: dd2ac143ce96ce406223a31c3ea8ae5116fd748c [file] [log] [blame]
Patrick Venture690a2342020-05-17 11:51:31 -07001#include "transporthandler.hpp"
2
William A. Kennington IIIc514d872019-04-06 18:19:38 -07003using phosphor::logging::commit;
4using phosphor::logging::elog;
5using phosphor::logging::entry;
6using phosphor::logging::level;
7using phosphor::logging::log;
8using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Johnathan Mantey65265362019-11-14 11:24:19 -08009using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070010using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070011using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070012
Johnathan Manteyaffadb52019-10-07 10:13:53 -070013namespace cipher
14{
15
16std::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
46namespace ipmi
47{
48namespace transport
49{
50
William A. Kennington IIIc514d872019-04-06 18:19:38 -070051/** @brief Valid address origins for IPv4 */
52const std::unordered_set<IP::AddressOrigin> originsV4 = {
53 IP::AddressOrigin::Static,
54 IP::AddressOrigin::DHCP,
55};
56
Johnathan Manteyb87034e2019-09-16 10:50:50 -070057static constexpr uint8_t oemCmdStart = 192;
58static constexpr uint8_t oemCmdEnd = 255;
59
Patrick Williams5d82f472022-07-22 19:26:53 -050060std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus_t& bus,
William A. Kennington IIIc514d872019-04-06 18:19:38 -070061 uint8_t channel)
62{
63 auto ifname = getChannelName(channel);
64 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080065 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -070066 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080067 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080068
William A. Kennington IIIc514d872019-04-06 18:19:38 -070069 // 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);
Willy Tu11d68892022-01-20 10:37:34 -0800128 return params;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700129}
130
Patrick Williams5d82f472022-07-22 19:26:53 -0500131ChannelParams getChannelParams(sdbusplus::bus_t& bus, uint8_t channel)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700132{
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 */
148template <auto level, typename... Args>
149auto 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}
155template <auto level, typename... Args>
156auto 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
Patrick Williams5d82f472022-07-22 19:26:53 -0500165EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus_t& bus,
Johnathan Mantey65265362019-11-14 11:24:19 -0800166 const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700167{
Johnathan Mantey65265362019-11-14 11:24:19 -0800168 std::string dhcpstr = std::get<std::string>(getDbusProperty(
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700169 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
Johnathan Mantey65265362019-11-14 11:24:19 -0800170 return EthernetInterface::convertDHCPConfFromString(dhcpstr);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700171}
172
Johnathan Mantey65265362019-11-14 11:24:19 -0800173/** @brief Sets the DHCP v4 state on the given interface
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700174 *
Johnathan Mantey65265362019-11-14 11:24:19 -0800175 * @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)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700182 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500183void setDHCPv4Property(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey65265362019-11-14 11:24:19 -0800184 const EthernetInterface::DHCPConf requestedDhcp)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700185{
Johnathan Mantey65265362019-11-14 11:24:19 -0800186 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
187 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
188
Tony Leed5967af2021-07-06 15:49:11 +0800189 // When calling setDHCPv4Property, requestedDhcp only has "v4" and "none".
190 // setDHCPv4Property is only for IPv4 management. It should not modify
191 // IPv6 state.
192 if (requestedDhcp == EthernetInterface::DHCPConf::v4)
Johnathan Mantey65265362019-11-14 11:24:19 -0800193 {
Tony Leed5967af2021-07-06 15:49:11 +0800194 if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
195 (currentDhcp == EthernetInterface::DHCPConf::both))
196 nextDhcp = EthernetInterface::DHCPConf::both;
197 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
198 (currentDhcp == EthernetInterface::DHCPConf::none))
199 nextDhcp = EthernetInterface::DHCPConf::v4;
Johnathan Mantey65265362019-11-14 11:24:19 -0800200 }
201 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
202 {
Tony Leed5967af2021-07-06 15:49:11 +0800203 if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
204 (currentDhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey65265362019-11-14 11:24:19 -0800205 nextDhcp = EthernetInterface::DHCPConf::v6;
Tony Leed5967af2021-07-06 15:49:11 +0800206 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
207 (currentDhcp == EthernetInterface::DHCPConf::none))
Johnathan Mantey65265362019-11-14 11:24:19 -0800208 nextDhcp = EthernetInterface::DHCPConf::none;
Johnathan Mantey65265362019-11-14 11:24:19 -0800209 }
Tony Leed5967af2021-07-06 15:49:11 +0800210 else // Stay the same.
Johnathan Mantey65265362019-11-14 11:24:19 -0800211 {
212 nextDhcp = currentDhcp;
213 }
214 std::string newDhcp =
215 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
216 nextDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700217 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800218 "DHCPEnabled", newDhcp);
219}
220
Patrick Williams5d82f472022-07-22 19:26:53 -0500221void setDHCPv6Property(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey65265362019-11-14 11:24:19 -0800222 const EthernetInterface::DHCPConf requestedDhcp,
223 const bool defaultMode = true)
224{
225 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
226 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
227
228 if (defaultMode)
229 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800230 // When calling setDHCPv6Property, requestedDhcp only has "v6" and
231 // "none".
232 // setDHCPv6Property is only for IPv6 management. It should not modify
233 // IPv4 state.
234 if (requestedDhcp == EthernetInterface::DHCPConf::v6)
Johnathan Mantey65265362019-11-14 11:24:19 -0800235 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800236 if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
237 (currentDhcp == EthernetInterface::DHCPConf::both))
238 nextDhcp = EthernetInterface::DHCPConf::both;
239 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
240 (currentDhcp == EthernetInterface::DHCPConf::none))
241 nextDhcp = EthernetInterface::DHCPConf::v6;
Johnathan Mantey65265362019-11-14 11:24:19 -0800242 }
243 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
244 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800245 if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
246 (currentDhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey65265362019-11-14 11:24:19 -0800247 nextDhcp = EthernetInterface::DHCPConf::v4;
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800248 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
249 (currentDhcp == EthernetInterface::DHCPConf::none))
Johnathan Mantey65265362019-11-14 11:24:19 -0800250 nextDhcp = EthernetInterface::DHCPConf::none;
Johnathan Mantey65265362019-11-14 11:24:19 -0800251 }
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800252 else // Stay the same.
Johnathan Mantey65265362019-11-14 11:24:19 -0800253 {
254 nextDhcp = currentDhcp;
255 }
256 }
257 else
258 {
259 // allow the v6 call to set any value
260 nextDhcp = requestedDhcp;
261 }
262
263 std::string newDhcp =
264 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
265 nextDhcp);
266 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
267 "DHCPEnabled", newDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700268}
269
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700270ether_addr stringToMAC(const char* mac)
271{
272 const ether_addr* ret = ether_aton(mac);
273 if (ret == nullptr)
274 {
275 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
276 elog<InternalFailure>();
277 }
278 return *ret;
279}
280
281/** @brief Determines the MAC of the ethernet interface
282 *
283 * @param[in] bus - The bus object used for lookups
284 * @param[in] params - The parameters for the channel
285 * @return The configured mac address
286 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500287ether_addr getMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700288{
289 auto macStr = std::get<std::string>(getDbusProperty(
290 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
291 return stringToMAC(macStr.c_str());
292}
293
294/** @brief Sets the system value for MAC address on the given interface
295 *
296 * @param[in] bus - The bus object used for lookups
297 * @param[in] params - The parameters for the channel
298 * @param[in] mac - MAC address to apply
299 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500300void setMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700301 const ether_addr& mac)
302{
303 std::string macStr = ether_ntoa(&mac);
304 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
305 macStr);
306}
307
Patrick Williams5d82f472022-07-22 19:26:53 -0500308void deleteObjectIfExists(sdbusplus::bus_t& bus, const std::string& service,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700309 const std::string& path)
310{
311 if (path.empty())
312 {
313 return;
314 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530315 try
tomjose26e17732016-03-03 08:52:51 -0600316 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700317 auto req = bus.new_method_call(service.c_str(), path.c_str(),
318 ipmi::DELETE_INTERFACE, "Delete");
319 bus.call_noreply(req);
320 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500321 catch (const sdbusplus::exception_t& e)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700322 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000323 if (strcmp(e.name(),
324 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
325 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600326 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700327 // We want to rethrow real errors
328 throw;
tomjose26e17732016-03-03 08:52:51 -0600329 }
330 }
tomjose26e17732016-03-03 08:52:51 -0600331}
332
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700333/** @brief Sets the address info configured for the interface
334 * If a previous address path exists then it will be removed
335 * before the new address is added.
336 *
337 * @param[in] bus - The bus object used for lookups
338 * @param[in] params - The parameters for the channel
339 * @param[in] address - The address of the new IP
340 * @param[in] prefix - The prefix of the new IP
341 */
342template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500343void createIfAddr(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700344 const typename AddrFamily<family>::addr& address,
345 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530346{
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500347 auto newreq = bus.new_method_call(params.service.c_str(),
348 params.logicalPath.c_str(),
349 INTF_IP_CREATE, "IP");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700350 std::string protocol =
351 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
352 AddrFamily<family>::protocol);
353 newreq.append(protocol, addrToString<family>(address), prefix, "");
354 bus.call_noreply(newreq);
355}
Tom Josepha30c8d32018-03-22 02:15:03 +0530356
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700357/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
358 *
359 * @param[in] bus - The bus object used for lookups
360 * @param[in] params - The parameters for the channel
361 * @return The address and prefix if found
362 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500363auto getIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530364{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700365 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
366}
Tom Josepha30c8d32018-03-22 02:15:03 +0530367
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700368/** @brief Reconfigures the IPv4 address info configured for the interface
369 *
370 * @param[in] bus - The bus object used for lookups
371 * @param[in] params - The parameters for the channel
372 * @param[in] address - The new address if specified
373 * @param[in] prefix - The new address prefix if specified
374 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500375void reconfigureIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700376 const std::optional<in_addr>& address,
377 std::optional<uint8_t> prefix)
378{
379 auto ifaddr = getIfAddr4(bus, params);
380 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530381 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700382 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530383 elog<InternalFailure>();
384 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700385 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
386 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530387 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700388 fallbackPrefix = ifaddr->prefix;
389 deleteObjectIfExists(bus, params.service, ifaddr->path);
390 }
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700391
Jian Zhangd05b9dd2023-07-04 14:48:40 +0800392 if (struct in_addr nullIPv4{0};
Jayaprakash Mutyala4e02b432023-07-13 13:50:40 +0000393 (address == std::nullopt && prefix != std::nullopt) ||
394 (address != std::nullopt &&
395 (address.value().s_addr != nullIPv4.s_addr)))
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700396 {
397 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
398 prefix.value_or(fallbackPrefix));
399 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700400}
401
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700402template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500403std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700404 const ChannelParams& params,
405 ObjectLookupCache& neighbors)
406{
407 auto gateway = getGatewayProperty<family>(bus, params);
408 if (!gateway)
409 {
410 return std::nullopt;
411 }
412
413 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
414}
415
416template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500417std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700418 const ChannelParams& params)
419{
420 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
421 return findGatewayNeighbor<family>(bus, params, neighbors);
422}
423
424template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500425void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
426 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700427{
428 auto gateway = getGatewayProperty<family>(bus, params);
429 if (!gateway)
430 {
431 log<level::ERR>("Tried to set Gateway MAC without Gateway");
432 elog<InternalFailure>();
433 }
434
435 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500436 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
437 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700438 if (neighbor)
439 {
440 deleteObjectIfExists(bus, params.service, neighbor->path);
441 }
442
443 createNeighbor<family>(bus, params, *gateway, mac);
444}
445
William A. Kennington III16064aa2019-04-13 17:44:53 -0700446/** @brief Deconfigures the IPv6 address info configured for the interface
447 *
448 * @param[in] bus - The bus object used for lookups
449 * @param[in] params - The parameters for the channel
450 * @param[in] idx - The address index to operate on
451 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500452void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700453 uint8_t idx)
454{
455 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
456 if (ifaddr)
457 {
458 deleteObjectIfExists(bus, params.service, ifaddr->path);
459 }
460}
461
462/** @brief Reconfigures the IPv6 address info configured for the interface
463 *
464 * @param[in] bus - The bus object used for lookups
465 * @param[in] params - The parameters for the channel
466 * @param[in] idx - The address index to operate on
467 * @param[in] address - The new address
468 * @param[in] prefix - The new address prefix
469 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500470void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700471 uint8_t idx, const in6_addr& address, uint8_t prefix)
472{
473 deconfigureIfAddr6(bus, params, idx);
474 createIfAddr<AF_INET6>(bus, params, address, prefix);
475}
476
477/** @brief Converts the AddressOrigin into an IPv6Source
478 *
479 * @param[in] origin - The DBus Address Origin to convert
480 * @return The IPv6Source version of the origin
481 */
482IPv6Source originToSourceType(IP::AddressOrigin origin)
483{
484 switch (origin)
485 {
486 case IP::AddressOrigin::Static:
487 return IPv6Source::Static;
488 case IP::AddressOrigin::DHCP:
489 return IPv6Source::DHCP;
490 case IP::AddressOrigin::SLAAC:
491 return IPv6Source::SLAAC;
492 default:
493 {
494 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
495 convertForMessage(origin);
496 log<level::ERR>(
497 "Invalid IP::AddressOrigin conversion to IPv6Source",
498 entry("ORIGIN=%s", originStr.c_str()));
499 elog<InternalFailure>();
500 }
501 }
502}
503
504/** @brief Packs the IPMI message response with IPv6 address data
505 *
506 * @param[out] ret - The IPMI response payload to be packed
507 * @param[in] channel - The channel id corresponding to an ethernet interface
508 * @param[in] set - The set selector for determining address index
509 * @param[in] origins - Set of valid origins for address filtering
510 */
511void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
512 const std::unordered_set<IP::AddressOrigin>& origins)
513{
514 auto source = IPv6Source::Static;
515 bool enabled = false;
516 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700517 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700518 auto status = IPv6AddressStatus::Disabled;
519
520 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
521 if (ifaddr)
522 {
523 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700524 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700525 addr = ifaddr->address;
526 prefix = ifaddr->prefix;
527 status = IPv6AddressStatus::Active;
528 }
529
530 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700531 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700532 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
533 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700534 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700535}
536
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700537/** @brief Gets the vlan ID configured on the interface
538 *
539 * @param[in] bus - The bus object used for lookups
540 * @param[in] params - The parameters for the channel
541 * @return VLAN id or the standard 0 for no VLAN
542 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500543uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700544{
545 // VLAN devices will always have a separate logical object
546 if (params.ifPath == params.logicalPath)
547 {
548 return 0;
549 }
550
551 auto vlan = std::get<uint32_t>(getDbusProperty(
552 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
553 if ((vlan & VLAN_VALUE_MASK) != vlan)
554 {
555 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
556 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530557 elog<InternalFailure>();
558 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700559 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530560}
561
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700562/** @brief Deletes all of the possible configuration parameters for a channel
563 *
564 * @param[in] bus - The bus object used for lookups
565 * @param[in] params - The parameters for the channel
566 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500567void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500568{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700569 // Delete all objects associated with the interface
570 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
571 "GetSubTree");
572 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
573 auto objreply = bus.call(objreq);
574 ObjectTree objs;
575 objreply.read(objs);
576 for (const auto& [path, impls] : objs)
577 {
578 if (path.find(params.ifname) == path.npos)
579 {
580 continue;
581 }
582 for (const auto& [service, intfs] : impls)
583 {
584 deleteObjectIfExists(bus, service, path);
585 }
586 // Update params to reflect the deletion of vlan
587 if (path == params.logicalPath)
588 {
589 params.logicalPath = params.ifPath;
590 }
591 }
592
593 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800594 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500595}
596
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700597/** @brief Creates a new VLAN on the specified interface
598 *
599 * @param[in] bus - The bus object used for lookups
600 * @param[in] params - The parameters for the channel
601 * @param[in] vlan - The id of the new vlan
602 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500603void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530604{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700605 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530606 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700607 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530608 }
609
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700610 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
611 INTF_VLAN_CREATE, "VLAN");
612 req.append(params.ifname, static_cast<uint32_t>(vlan));
613 auto reply = bus.call(req);
614 sdbusplus::message::object_path newPath;
615 reply.read(newPath);
616 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530617}
618
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700619/** @brief Performs the necessary reconfiguration to change the VLAN
620 *
621 * @param[in] bus - The bus object used for lookups
622 * @param[in] params - The parameters for the channel
623 * @param[in] vlan - The new vlan id to use
624 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500625void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700626 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500627{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700628 // Unfortunatetly we don't have built-in functions to migrate our interface
629 // customizations to new VLAN interfaces, or have some kind of decoupling.
630 // We therefore must retain all of our old information, setup the new VLAN
631 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800632
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700633 // Save info from the old logical interface
634 ObjectLookupCache ips(bus, params, INTF_IP);
635 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700636 std::vector<IfAddr<AF_INET6>> ifaddrs6;
637 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
638 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500639 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
640 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700641 if (!ifaddr6)
642 {
643 break;
644 }
645 ifaddrs6.push_back(std::move(*ifaddr6));
646 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800647 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700648 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
649 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700650 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500651
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700652 deconfigureChannel(bus, params);
653 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500654
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700655 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800656 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700657 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800658 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700659 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800660 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700661 for (const auto& ifaddr6 : ifaddrs6)
662 {
663 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
664 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700665 if (neighbor4)
666 {
667 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
668 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700669 if (neighbor6)
670 {
671 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
672 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700673}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800674
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700675/** @brief Turns a prefix into a netmask
676 *
677 * @param[in] prefix - The prefix length
678 * @return The netmask
679 */
680in_addr prefixToNetmask(uint8_t prefix)
681{
682 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500683 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700684 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
685 elog<InternalFailure>();
686 }
687 if (prefix == 0)
688 {
689 // Avoids 32-bit lshift by 32 UB
690 return {};
691 }
692 return {htobe32(~UINT32_C(0) << (32 - prefix))};
693}
694
695/** @brief Turns a a netmask into a prefix length
696 *
697 * @param[in] netmask - The netmask in byte form
698 * @return The prefix length
699 */
700uint8_t netmaskToPrefix(in_addr netmask)
701{
702 uint32_t x = be32toh(netmask.s_addr);
703 if ((~x & (~x + 1)) != 0)
704 {
705 char maskStr[INET_ADDRSTRLEN];
706 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
707 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
708 elog<InternalFailure>();
709 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800710 return static_cast<bool>(x)
711 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
712 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700713}
714
715// We need to store this value so it can be returned to the client
716// It is volatile so safe to store in daemon memory.
717static std::unordered_map<uint8_t, SetStatus> setStatus;
718
719// Until we have good support for fixed versions of IPMI tool
720// we need to return the VLAN id for disabled VLANs. The value is only
721// used for verification that a disable operation succeeded and will only
722// be sent if our system indicates that vlans are disabled.
723static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
724
725/** @brief Gets the set status for the channel if it exists
726 * Otherise populates and returns the default value.
727 *
728 * @param[in] channel - The channel id corresponding to an ethernet interface
729 * @return A reference to the SetStatus for the channel
730 */
731SetStatus& getSetStatus(uint8_t channel)
732{
733 auto it = setStatus.find(channel);
734 if (it != setStatus.end())
735 {
736 return it->second;
737 }
738 return setStatus[channel] = SetStatus::Complete;
739}
740
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800741/** @brief Gets the IPv6 Router Advertisement value
742 *
743 * @param[in] bus - The bus object used for lookups
744 * @param[in] params - The parameters for the channel
745 * @return networkd IPV6AcceptRA value
746 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500747static bool getIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params)
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800748{
749 auto raEnabled =
750 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
751 INTF_ETHERNET, "IPv6AcceptRA"));
752 return raEnabled;
753}
754
755/** @brief Sets the IPv6AcceptRA flag
756 *
757 * @param[in] bus - The bus object used for lookups
758 * @param[in] params - The parameters for the channel
759 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
760 * Advertisement
761 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500762void setIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800763 const bool ipv6AcceptRA)
764{
765 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
766 "IPv6AcceptRA", ipv6AcceptRA);
767}
768
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700769/**
770 * Define placeholder command handlers for the OEM Extension bytes for the Set
771 * LAN Configuration Parameters and Get LAN Configuration Parameters
772 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
773 * functions below to be overridden.
774 * To create handlers for your own proprietary command set:
775 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
776 * recipe
777 * Create C++ file(s) that define IPMI handler functions matching the
778 * function names below (i.e. setLanOem). The default name for the
779 * transport IPMI commands is transporthandler_oem.cpp.
780 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700781 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
782 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700783 * bbappend file to copy the file to the build directory.
784 * Add:
785 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
786 * # Copy the "strong" functions into the working directory, overriding the
787 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700788 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700789 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
790 * }
791 *
792 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700793 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700794 * rm -f ${S}/transporthandler_oem.cpp
795 * }
796 *
797 */
798
799/**
800 * Define the placeholder OEM commands as having weak linkage. Create
801 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
802 * file. The functions defined there must not have the "weak" attribute
803 * applied to them.
804 */
805RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
806 __attribute__((weak));
807RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
808 uint8_t set, uint8_t block)
809 __attribute__((weak));
810
Willy Tu11d68892022-01-20 10:37:34 -0800811RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700812{
813 req.trailingOk = true;
814 return response(ccParamNotSupported);
815}
816
Willy Tu11d68892022-01-20 10:37:34 -0800817RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700818{
819 return response(ccParamNotSupported);
820}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530821/**
822 * @brief is MAC address valid.
823 *
824 * This function checks whether the MAC address is valid or not.
825 *
826 * @param[in] mac - MAC address.
827 * @return true if MAC address is valid else retun false.
828 **/
829bool isValidMACAddress(const ether_addr& mac)
830{
831 // check if mac address is empty
832 if (equal(mac, ether_addr{}))
833 {
834 return false;
835 }
836 // we accept only unicast MAC addresses and same thing has been checked in
837 // phosphor-network layer. If the least significant bit of the first octet
838 // is set to 1, it is multicast MAC else it is unicast MAC address.
839 if (mac.ether_addr_octet[0] & 1)
840 {
841 return false;
842 }
843 return true;
844}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700845
Jian Zhangcf19d142023-07-31 10:22:53 +0800846/**
847 * @brief is a valid LAN channel.
848 *
849 * This function checks whether the input channel is a valid LAN channel or not.
850 *
851 * @param[in] channel: the channel number.
852 * @return nullopt if the channel is invalid, false if the channel is not a LAN
853 * channel, true if the channel is a LAN channel.
854 **/
855std::optional<bool> isLanChannel(uint8_t channel)
856{
857 ChannelInfo chInfo;
858 auto cc = getChannelInfo(channel, chInfo);
859 if (cc != ccSuccess)
860 {
861 return std::nullopt;
862 }
863
864 return chInfo.mediumType ==
865 static_cast<uint8_t>(EChannelMediumType::lan8032);
866}
867
vijayabharathix shettycc769252020-02-27 17:52:20 +0000868RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
869 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700870{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000871 const uint8_t channel = convertCurrentChannelNum(
872 static_cast<uint8_t>(channelBits), ctx->channel);
873 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700874 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000875 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700876 req.trailingOk = true;
877 return responseInvalidFieldRequest();
878 }
879
Jian Zhangcf19d142023-07-31 10:22:53 +0800880 if (!isLanChannel(channel).value_or(false))
881 {
882 log<level::ERR>("Set Lan - Not a LAN channel");
883 return responseInvalidFieldRequest();
884 }
885
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700886 switch (static_cast<LanParam>(parameter))
887 {
888 case LanParam::SetStatus:
889 {
890 uint2_t flag;
891 uint6_t rsvd;
892 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
893 {
894 return responseReqDataLenInvalid();
895 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800896 if (rsvd)
897 {
898 return responseInvalidFieldRequest();
899 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700900 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
901 switch (status)
902 {
903 case SetStatus::Complete:
904 {
905 getSetStatus(channel) = status;
906 return responseSuccess();
907 }
908 case SetStatus::InProgress:
909 {
910 auto& storedStatus = getSetStatus(channel);
911 if (storedStatus == SetStatus::InProgress)
912 {
913 return response(ccParamSetLocked);
914 }
915 storedStatus = status;
916 return responseSuccess();
917 }
918 case SetStatus::Commit:
919 if (getSetStatus(channel) != SetStatus::InProgress)
920 {
921 return responseInvalidFieldRequest();
922 }
923 return responseSuccess();
924 }
925 return response(ccParamNotSupported);
926 }
927 case LanParam::AuthSupport:
928 {
929 req.trailingOk = true;
930 return response(ccParamReadOnly);
931 }
932 case LanParam::AuthEnables:
933 {
934 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800935 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700936 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800937 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600938 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800939 EthernetInterface::DHCPConf dhcp =
940 channelCall<getDHCPProperty>(channel);
941 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
942 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800943 {
944 return responseCommandNotAvailable();
945 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700946 in_addr ip;
947 std::array<uint8_t, sizeof(ip)> bytes;
948 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
949 {
950 return responseReqDataLenInvalid();
951 }
952 copyInto(ip, bytes);
953 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
954 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530955 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700956 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530957 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700958 uint4_t flag;
959 uint4_t rsvd;
960 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
961 {
962 return responseReqDataLenInvalid();
963 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800964 if (rsvd)
965 {
966 return responseInvalidFieldRequest();
967 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700968 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
969 {
970 case IPSrc::DHCP:
971 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800972 // The IPSrc IPMI command is only for IPv4
973 // management. Modifying IPv6 state is done using
974 // a completely different Set LAN Configuration
975 // subcommand.
976 channelCall<setDHCPv4Property>(
977 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700978 return responseSuccess();
979 }
980 case IPSrc::Unspecified:
981 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700982 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800983 channelCall<setDHCPv4Property>(
984 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700985 return responseSuccess();
986 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530987 case IPSrc::BIOS:
988 case IPSrc::BMC:
989 {
990 return responseInvalidFieldRequest();
991 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700992 }
993 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530994 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800995 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530996 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700997 ether_addr mac;
998 std::array<uint8_t, sizeof(mac)> bytes;
999 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301000 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001001 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +05301002 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001003 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +05301004
1005 if (!isValidMACAddress(mac))
1006 {
1007 return responseInvalidFieldRequest();
1008 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001009 channelCall<setMACProperty>(channel, mac);
1010 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +05301011 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001012 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +05301013 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001014 EthernetInterface::DHCPConf dhcp =
1015 channelCall<getDHCPProperty>(channel);
1016 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1017 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001018 {
1019 return responseCommandNotAvailable();
1020 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001021 in_addr netmask;
1022 std::array<uint8_t, sizeof(netmask)> bytes;
1023 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +05301024 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001025 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +05301026 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001027 copyInto(netmask, bytes);
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001028 uint8_t prefix = netmaskToPrefix(netmask);
1029 if (prefix < MIN_IPV4_PREFIX_LENGTH)
1030 {
1031 return responseInvalidFieldRequest();
1032 }
1033 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001034 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301035 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001036 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301037 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001038 EthernetInterface::DHCPConf dhcp =
1039 channelCall<getDHCPProperty>(channel);
1040 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1041 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001042 {
1043 return responseCommandNotAvailable();
1044 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001045 in_addr gateway;
1046 std::array<uint8_t, sizeof(gateway)> bytes;
1047 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1048 {
1049 return responseReqDataLenInvalid();
1050 }
1051 copyInto(gateway, bytes);
1052 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1053 return responseSuccess();
1054 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001055 case LanParam::Gateway1MAC:
1056 {
1057 ether_addr gatewayMAC;
1058 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1059 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1060 {
1061 return responseReqDataLenInvalid();
1062 }
1063 copyInto(gatewayMAC, bytes);
1064 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1065 return responseSuccess();
1066 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001067 case LanParam::VLANId:
1068 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301069 uint12_t vlanData = 0;
1070 uint3_t reserved = 0;
1071 bool vlanEnable = 0;
1072
1073 if (req.unpack(vlanData) || req.unpack(reserved) ||
1074 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001075 {
1076 return responseReqDataLenInvalid();
1077 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301078
1079 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001080 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301081 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001082 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301083
1084 uint16_t vlan = static_cast<uint16_t>(vlanData);
1085
1086 if (!vlanEnable)
1087 {
1088 lastDisabledVlan[channel] = vlan;
1089 vlan = 0;
1090 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001091 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1092 {
1093 return responseInvalidFieldRequest();
1094 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301095
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001096 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001097 return responseSuccess();
1098 }
1099 case LanParam::CiphersuiteSupport:
1100 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001101 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001102 {
1103 req.trailingOk = true;
1104 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301105 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001106 case LanParam::IPFamilyEnables:
1107 {
1108 uint8_t enables;
1109 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1110 {
1111 return responseReqDataLenInvalid();
1112 }
1113 switch (static_cast<IPFamilyEnables>(enables))
1114 {
1115 case IPFamilyEnables::DualStack:
1116 return responseSuccess();
1117 case IPFamilyEnables::IPv4Only:
1118 case IPFamilyEnables::IPv6Only:
1119 return response(ccParamNotSupported);
1120 }
1121 return response(ccParamNotSupported);
1122 }
1123 case LanParam::IPv6Status:
1124 {
1125 req.trailingOk = true;
1126 return response(ccParamReadOnly);
1127 }
1128 case LanParam::IPv6StaticAddresses:
1129 {
1130 uint8_t set;
1131 uint7_t rsvd;
1132 bool enabled;
1133 in6_addr ip;
1134 std::array<uint8_t, sizeof(ip)> ipbytes;
1135 uint8_t prefix;
1136 uint8_t status;
1137 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1138 !req.fullyUnpacked())
1139 {
1140 return responseReqDataLenInvalid();
1141 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001142 if (rsvd)
1143 {
1144 return responseInvalidFieldRequest();
1145 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001146 copyInto(ip, ipbytes);
1147 if (enabled)
1148 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001149 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
1150 prefix > MAX_IPV6_PREFIX_LENGTH)
1151 {
1152 return responseParmOutOfRange();
1153 }
Johnathan Manteya291f492021-10-15 13:45:27 -07001154 try
1155 {
1156 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1157 }
Patrick Williams5d82f472022-07-22 19:26:53 -05001158 catch (const sdbusplus::exception_t& e)
Johnathan Manteya291f492021-10-15 13:45:27 -07001159 {
1160 if (std::string_view err{
1161 "xyz.openbmc_project.Common.Error.InvalidArgument"};
1162 err == e.name())
1163 {
1164 return responseInvalidFieldRequest();
1165 }
1166 else
1167 {
1168 throw;
1169 }
1170 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001171 }
1172 else
1173 {
1174 channelCall<deconfigureIfAddr6>(channel, set);
1175 }
1176 return responseSuccess();
1177 }
1178 case LanParam::IPv6DynamicAddresses:
1179 {
1180 req.trailingOk = true;
1181 return response(ccParamReadOnly);
1182 }
1183 case LanParam::IPv6RouterControl:
1184 {
1185 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001186 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001187 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1188 {
1189 return responseReqDataLenInvalid();
1190 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001191 if (std::bitset<8> expected(control &
1192 std::bitset<8>(reservedRACCBits));
1193 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001194 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001195 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001196 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001197
1198 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1199 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001200 return responseSuccess();
1201 }
1202 case LanParam::IPv6StaticRouter1IP:
1203 {
1204 in6_addr gateway;
1205 std::array<uint8_t, sizeof(gateway)> bytes;
1206 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1207 {
1208 return responseReqDataLenInvalid();
1209 }
1210 copyInto(gateway, bytes);
1211 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1212 return responseSuccess();
1213 }
1214 case LanParam::IPv6StaticRouter1MAC:
1215 {
1216 ether_addr mac;
1217 std::array<uint8_t, sizeof(mac)> bytes;
1218 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1219 {
1220 return responseReqDataLenInvalid();
1221 }
1222 copyInto(mac, bytes);
1223 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1224 return responseSuccess();
1225 }
1226 case LanParam::IPv6StaticRouter1PrefixLength:
1227 {
1228 uint8_t prefix;
1229 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1230 {
1231 return responseReqDataLenInvalid();
1232 }
1233 if (prefix != 0)
1234 {
1235 return responseInvalidFieldRequest();
1236 }
1237 return responseSuccess();
1238 }
1239 case LanParam::IPv6StaticRouter1PrefixValue:
1240 {
1241 std::array<uint8_t, sizeof(in6_addr)> bytes;
1242 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1243 {
1244 return responseReqDataLenInvalid();
1245 }
1246 // Accept any prefix value since our prefix length has to be 0
1247 return responseSuccess();
1248 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001249 case LanParam::cipherSuitePrivilegeLevels:
1250 {
1251 uint8_t reserved;
1252 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1253
1254 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1255 {
1256 return responseReqDataLenInvalid();
1257 }
1258
1259 if (reserved)
1260 {
1261 return responseInvalidFieldRequest();
1262 }
1263
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001264 uint8_t resp = getCipherConfigObject(csPrivFileName,
1265 csPrivDefaultFileName)
1266 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001267 if (!resp)
1268 {
1269 return responseSuccess();
1270 }
1271 else
1272 {
1273 req.trailingOk = true;
1274 return response(resp);
1275 }
1276 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301277 }
vishwa1eaea4f2016-02-26 11:57:40 -06001278
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001279 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1280 {
1281 return setLanOem(channel, parameter, req);
1282 }
1283
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001284 req.trailingOk = true;
1285 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001286}
1287
vijayabharathix shettycc769252020-02-27 17:52:20 +00001288RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1289 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001290 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301291{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001292 message::Payload ret;
1293 constexpr uint8_t current_revision = 0x11;
1294 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001295
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001296 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301297 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001298 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301299 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001300
vijayabharathix shettycc769252020-02-27 17:52:20 +00001301 const uint8_t channel = convertCurrentChannelNum(
1302 static_cast<uint8_t>(channelBits), ctx->channel);
1303 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001304 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001305 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001306 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001307 }
1308
Jian Zhangcf19d142023-07-31 10:22:53 +08001309 if (!isLanChannel(channel).value_or(false))
1310 {
1311 log<level::ERR>("Set Lan - Not a LAN channel");
1312 return responseInvalidFieldRequest();
1313 }
1314
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001315 static std::vector<uint8_t> cipherList;
1316 static bool listInit = false;
1317 if (!listInit)
1318 {
1319 try
1320 {
1321 cipherList = cipher::getCipherList();
1322 listInit = true;
1323 }
1324 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001325 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001326 }
1327
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001328 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301329 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001330 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301331 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001332 SetStatus status;
1333 try
1334 {
1335 status = setStatus.at(channel);
1336 }
1337 catch (const std::out_of_range&)
1338 {
1339 status = SetStatus::Complete;
1340 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001341 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001342 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301343 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001344 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301345 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001346 std::bitset<6> support;
1347 ret.pack(support, uint2_t{});
1348 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301349 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001350 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001351 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001352 std::bitset<6> enables;
1353 ret.pack(enables, uint2_t{}); // Callback
1354 ret.pack(enables, uint2_t{}); // User
1355 ret.pack(enables, uint2_t{}); // Operator
1356 ret.pack(enables, uint2_t{}); // Admin
1357 ret.pack(enables, uint2_t{}); // OEM
1358 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001359 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001360 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001361 {
1362 auto ifaddr = channelCall<getIfAddr4>(channel);
1363 in_addr addr{};
1364 if (ifaddr)
1365 {
1366 addr = ifaddr->address;
1367 }
1368 ret.pack(dataRef(addr));
1369 return responseSuccess(std::move(ret));
1370 }
1371 case LanParam::IPSrc:
1372 {
1373 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001374 EthernetInterface::DHCPConf dhcp =
1375 channelCall<getDHCPProperty>(channel);
1376 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1377 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001378 {
1379 src = IPSrc::DHCP;
1380 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001381 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001382 return responseSuccess(std::move(ret));
1383 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001384 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001385 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001386 ether_addr mac = channelCall<getMACProperty>(channel);
1387 ret.pack(dataRef(mac));
1388 return responseSuccess(std::move(ret));
1389 }
1390 case LanParam::SubnetMask:
1391 {
1392 auto ifaddr = channelCall<getIfAddr4>(channel);
1393 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1394 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301395 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001396 prefix = ifaddr->prefix;
1397 }
1398 in_addr netmask = prefixToNetmask(prefix);
1399 ret.pack(dataRef(netmask));
1400 return responseSuccess(std::move(ret));
1401 }
1402 case LanParam::Gateway1:
1403 {
1404 auto gateway =
1405 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1406 in_addr{});
1407 ret.pack(dataRef(gateway));
1408 return responseSuccess(std::move(ret));
1409 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001410 case LanParam::Gateway1MAC:
1411 {
1412 ether_addr mac{};
1413 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1414 if (neighbor)
1415 {
1416 mac = neighbor->mac;
1417 }
1418 ret.pack(dataRef(mac));
1419 return responseSuccess(std::move(ret));
1420 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001421 case LanParam::VLANId:
1422 {
1423 uint16_t vlan = channelCall<getVLANProperty>(channel);
1424 if (vlan != 0)
1425 {
1426 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301427 }
1428 else
1429 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001430 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301431 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001432 ret.pack(vlan);
1433 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001434 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001435 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001436 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001437 if (getChannelSessionSupport(channel) ==
1438 EChannelSessSupported::none)
1439 {
1440 return responseInvalidFieldRequest();
1441 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001442 if (!listInit)
1443 {
1444 return responseUnspecifiedError();
1445 }
1446 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1447 return responseSuccess(std::move(ret));
1448 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001449 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001450 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001451 if (getChannelSessionSupport(channel) ==
1452 EChannelSessSupported::none)
1453 {
1454 return responseInvalidFieldRequest();
1455 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001456 if (!listInit)
1457 {
1458 return responseUnspecifiedError();
1459 }
1460 ret.pack(cipherList);
1461 return responseSuccess(std::move(ret));
1462 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001463 case LanParam::IPFamilySupport:
1464 {
1465 std::bitset<8> support;
1466 support[IPFamilySupportFlag::IPv6Only] = 0;
1467 support[IPFamilySupportFlag::DualStack] = 1;
1468 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1469 ret.pack(support);
1470 return responseSuccess(std::move(ret));
1471 }
1472 case LanParam::IPFamilyEnables:
1473 {
1474 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1475 return responseSuccess(std::move(ret));
1476 }
1477 case LanParam::IPv6Status:
1478 {
1479 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1480 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1481 std::bitset<8> support;
1482 support[IPv6StatusFlag::DHCP] = 1;
1483 support[IPv6StatusFlag::SLAAC] = 1;
1484 ret.pack(support);
1485 return responseSuccess(std::move(ret));
1486 }
1487 case LanParam::IPv6StaticAddresses:
1488 {
1489 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1490 {
1491 return responseParmOutOfRange();
1492 }
1493 getLanIPv6Address(ret, channel, set, originsV6Static);
1494 return responseSuccess(std::move(ret));
1495 }
1496 case LanParam::IPv6DynamicAddresses:
1497 {
1498 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1499 {
1500 return responseParmOutOfRange();
1501 }
1502 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1503 return responseSuccess(std::move(ret));
1504 }
1505 case LanParam::IPv6RouterControl:
1506 {
1507 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001508 control[IPv6RouterControlFlag::Dynamic] =
1509 channelCall<getIPv6AcceptRA>(channel);
1510 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001511 ret.pack(control);
1512 return responseSuccess(std::move(ret));
1513 }
1514 case LanParam::IPv6StaticRouter1IP:
1515 {
1516 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001517 EthernetInterface::DHCPConf dhcp =
1518 channelCall<getDHCPProperty>(channel);
1519 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1520 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001521 {
1522 gateway =
1523 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1524 in6_addr{});
1525 }
1526 ret.pack(dataRef(gateway));
1527 return responseSuccess(std::move(ret));
1528 }
1529 case LanParam::IPv6StaticRouter1MAC:
1530 {
1531 ether_addr mac{};
1532 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1533 if (neighbor)
1534 {
1535 mac = neighbor->mac;
1536 }
1537 ret.pack(dataRef(mac));
1538 return responseSuccess(std::move(ret));
1539 }
1540 case LanParam::IPv6StaticRouter1PrefixLength:
1541 {
1542 ret.pack(UINT8_C(0));
1543 return responseSuccess(std::move(ret));
1544 }
1545 case LanParam::IPv6StaticRouter1PrefixValue:
1546 {
1547 in6_addr prefix{};
1548 ret.pack(dataRef(prefix));
1549 return responseSuccess(std::move(ret));
1550 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001551 case LanParam::cipherSuitePrivilegeLevels:
1552 {
1553 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1554
1555 uint8_t resp =
1556 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1557 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1558 if (!resp)
1559 {
1560 constexpr uint8_t reserved1 = 0x00;
1561 ret.pack(reserved1, csPrivilegeLevels);
1562 return responseSuccess(std::move(ret));
1563 }
1564 else
1565 {
1566 return response(resp);
1567 }
1568 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001569 }
1570
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001571 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1572 {
1573 return getLanOem(channel, parameter, set, block);
1574 }
1575
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001576 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001577}
1578
Jian Zhang23f44652022-03-17 17:13:10 +08001579constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1580constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1581constexpr const uint16_t solDefaultPort = 623;
1582
1583RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001584 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001585 message::Payload& req)
1586{
1587 const uint8_t channel = convertCurrentChannelNum(
1588 static_cast<uint8_t>(channelBits), ctx->channel);
1589
1590 if (!isValidChannel(channel))
1591 {
1592 log<level::ERR>("Set Sol Config - Invalid channel in request");
1593 return responseInvalidFieldRequest();
1594 }
1595
1596 std::string solService{};
1597 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1598
1599 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1600 {
1601 log<level::ERR>("Set Sol Config - Invalid solInterface",
1602 entry("SERVICE=%s", solService.c_str()),
1603 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1604 entry("INTERFACE=%s", solInterface));
1605 return responseInvalidFieldRequest();
1606 }
1607
1608 switch (static_cast<SolConfParam>(parameter))
1609 {
1610 case SolConfParam::Progress:
1611 {
1612 uint8_t progress;
1613 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1614 {
1615 return responseReqDataLenInvalid();
1616 }
1617
1618 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1619 solInterface, "Progress", progress))
1620 {
1621 return responseUnspecifiedError();
1622 }
1623 break;
1624 }
1625 case SolConfParam::Enable:
1626 {
1627 bool enable;
1628 uint7_t reserved2;
1629
1630 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1631 {
1632 return responseReqDataLenInvalid();
1633 }
1634
1635 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1636 solInterface, "Enable", enable))
1637 {
1638 return responseUnspecifiedError();
1639 }
1640 break;
1641 }
1642 case SolConfParam::Authentication:
1643 {
1644 uint4_t privilegeBits{};
1645 uint2_t reserved2{};
1646 bool forceAuth = false;
1647 bool forceEncrypt = false;
1648
1649 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1650 0 ||
1651 !req.fullyUnpacked())
1652 {
1653 return responseReqDataLenInvalid();
1654 }
1655
1656 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001657 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001658 privilege > static_cast<uint8_t>(Privilege::Oem))
1659 {
1660 return ipmi::responseInvalidFieldRequest();
1661 }
1662
1663 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1664 solInterface, "Privilege", privilege))
1665 {
1666 return responseUnspecifiedError();
1667 }
1668
1669 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1670 solInterface, "ForceEncryption",
1671 forceEncrypt))
1672 {
1673 return responseUnspecifiedError();
1674 }
1675
1676 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1677 solInterface, "ForceAuthentication",
1678 forceAuth))
1679 {
1680 return responseUnspecifiedError();
1681 }
1682 break;
1683 }
1684 case SolConfParam::Accumulate:
1685 {
1686 uint8_t interval;
1687 uint8_t threshold;
1688 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1689 {
1690 return responseReqDataLenInvalid();
1691 }
1692
1693 if (threshold == 0)
1694 {
1695 return responseInvalidFieldRequest();
1696 }
1697
1698 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1699 solInterface, "AccumulateIntervalMS",
1700 interval))
1701 {
1702 return responseUnspecifiedError();
1703 }
1704
1705 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1706 solInterface, "Threshold", threshold))
1707 {
1708 return responseUnspecifiedError();
1709 }
1710 break;
1711 }
1712 case SolConfParam::Retry:
1713 {
1714 uint3_t countBits;
1715 uint5_t reserved2;
1716 uint8_t interval;
1717
1718 if (req.unpack(countBits, reserved2, interval) != 0 ||
1719 !req.fullyUnpacked())
1720 {
1721 return responseReqDataLenInvalid();
1722 }
1723
1724 uint8_t count = static_cast<uint8_t>(countBits);
1725 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1726 solInterface, "RetryCount", count))
1727 {
1728 return responseUnspecifiedError();
1729 }
1730
1731 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1732 solInterface, "RetryIntervalMS",
1733 interval))
1734 {
1735 return responseUnspecifiedError();
1736 }
1737 break;
1738 }
1739 case SolConfParam::Port:
1740 {
1741 return response(ipmiCCWriteReadParameter);
1742 }
1743 case SolConfParam::NonVbitrate:
1744 case SolConfParam::Vbitrate:
1745 case SolConfParam::Channel:
1746 default:
1747 return response(ipmiCCParamNotSupported);
1748 }
1749 return responseSuccess();
1750}
1751
1752RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1753 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001754 uint3_t /*reserved*/, bool revOnly,
1755 uint8_t parameter, uint8_t /*set*/,
1756 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001757{
1758 message::Payload ret;
1759 constexpr uint8_t current_revision = 0x11;
1760 ret.pack(current_revision);
1761 if (revOnly)
1762 {
1763 return responseSuccess(std::move(ret));
1764 }
1765
1766 const uint8_t channel = convertCurrentChannelNum(
1767 static_cast<uint8_t>(channelBits), ctx->channel);
1768
1769 if (!isValidChannel(channel))
1770 {
1771 log<level::ERR>("Get Sol Config - Invalid channel in request");
1772 return responseInvalidFieldRequest();
1773 }
1774
1775 std::string solService{};
1776 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1777
1778 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1779 {
1780 log<level::ERR>("Set Sol Config - Invalid solInterface",
1781 entry("SERVICE=%s", solService.c_str()),
1782 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1783 entry("INTERFACE=%s", solInterface));
1784 return responseInvalidFieldRequest();
1785 }
1786
1787 switch (static_cast<SolConfParam>(parameter))
1788 {
1789 case SolConfParam::Progress:
1790 {
1791 uint8_t progress;
1792 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1793 solInterface, "Progress", progress))
1794 {
1795 return responseUnspecifiedError();
1796 }
1797 ret.pack(progress);
1798 return responseSuccess(std::move(ret));
1799 }
1800 case SolConfParam::Enable:
1801 {
1802 bool enable{};
1803 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1804 solInterface, "Enable", enable))
1805 {
1806 return responseUnspecifiedError();
1807 }
1808 ret.pack(enable, uint7_t{});
1809 return responseSuccess(std::move(ret));
1810 }
1811 case SolConfParam::Authentication:
1812 {
1813 // 4bits, cast when pack
1814 uint8_t privilege;
1815 bool forceAuth = false;
1816 bool forceEncrypt = false;
1817
1818 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1819 solInterface, "Privilege", privilege))
1820 {
1821 return responseUnspecifiedError();
1822 }
1823
1824 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1825 solInterface, "ForceAuthentication",
1826 forceAuth))
1827 {
1828 return responseUnspecifiedError();
1829 }
1830
1831 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1832 solInterface, "ForceEncryption",
1833 forceEncrypt))
1834 {
1835 return responseUnspecifiedError();
1836 }
1837 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1838 return responseSuccess(std::move(ret));
1839 }
1840 case SolConfParam::Accumulate:
1841 {
1842 uint8_t interval{}, threshold{};
1843
1844 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1845 solInterface, "AccumulateIntervalMS",
1846 interval))
1847 {
1848 return responseUnspecifiedError();
1849 }
1850
1851 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1852 solInterface, "Threshold", threshold))
1853 {
1854 return responseUnspecifiedError();
1855 }
1856 ret.pack(interval, threshold);
1857 return responseSuccess(std::move(ret));
1858 }
1859 case SolConfParam::Retry:
1860 {
1861 // 3bits, cast when cast
1862 uint8_t count{};
1863 uint8_t interval{};
1864
1865 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1866 solInterface, "RetryCount", count))
1867 {
1868 return responseUnspecifiedError();
1869 }
1870
1871 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1872 solInterface, "RetryIntervalMS",
1873 interval))
1874 {
1875 return responseUnspecifiedError();
1876 }
1877 ret.pack(uint3_t{count}, uint5_t{}, interval);
1878 return responseSuccess(std::move(ret));
1879 }
1880 case SolConfParam::Port:
1881 {
1882 auto port = solDefaultPort;
1883 ret.pack(static_cast<uint16_t>(port));
1884 return responseSuccess(std::move(ret));
1885 }
1886 case SolConfParam::Channel:
1887 {
1888 ret.pack(channel);
1889 return responseSuccess(std::move(ret));
1890 }
1891 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001892 {
1893 uint64_t baudRate;
1894 uint8_t encodedBitRate = 0;
1895 if (ipmi::getDbusProperty(
1896 ctx, "xyz.openbmc_project.Console.default",
1897 "/xyz/openbmc_project/console/default",
1898 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1899 {
1900 return ipmi::responseUnspecifiedError();
1901 }
1902 switch (baudRate)
1903 {
1904 case 9600:
1905 encodedBitRate = 0x06;
1906 break;
1907 case 19200:
1908 encodedBitRate = 0x07;
1909 break;
1910 case 38400:
1911 encodedBitRate = 0x08;
1912 break;
1913 case 57600:
1914 encodedBitRate = 0x09;
1915 break;
1916 case 115200:
1917 encodedBitRate = 0x0a;
1918 break;
1919 default:
1920 break;
1921 }
1922 ret.pack(encodedBitRate);
1923 return responseSuccess(std::move(ret));
1924 }
Jian Zhang23f44652022-03-17 17:13:10 +08001925 case SolConfParam::Vbitrate:
1926 default:
1927 return response(ipmiCCParamNotSupported);
1928 }
1929
1930 return response(ccParamNotSupported);
1931}
1932
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001933} // namespace transport
1934} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301935
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001936void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301937
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001938void register_netfn_transport_functions()
1939{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001940 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1941 ipmi::transport::cmdSetLanConfigParameters,
1942 ipmi::Privilege::Admin, ipmi::transport::setLan);
1943 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1944 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001945 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001946 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1947 ipmi::transport::cmdSetSolConfigParameters,
1948 ipmi::Privilege::Admin,
1949 ipmi::transport::setSolConfParams);
1950 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1951 ipmi::transport::cmdGetSolConfigParameters,
1952 ipmi::Privilege::User,
1953 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001954}