blob: cacf2ec7a19c730f5027eaa60319b729e107d695 [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
William A. Kennington IIIc514d872019-04-06 18:19:38 -070060std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
61 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);
128 return std::move(params);
129}
130
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700131ChannelParams 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 */
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
Johnathan Mantey65265362019-11-14 11:24:19 -0800165EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus::bus& bus,
166 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 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800183void setDHCPv4Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
184 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
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);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700218 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800219 "DHCPEnabled", newDhcp);
220}
221
Johnathan Mantey65265362019-11-14 11:24:19 -0800222void 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);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700269}
270
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700271ether_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 */
288ether_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 */
301void 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
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700309void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
310 const std::string& path)
311{
312 if (path.empty())
313 {
314 return;
315 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530316 try
tomjose26e17732016-03-03 08:52:51 -0600317 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700318 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 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000324 if (strcmp(e.name(),
325 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
326 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600327 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700328 // We want to rethrow real errors
329 throw;
tomjose26e17732016-03-03 08:52:51 -0600330 }
331 }
tomjose26e17732016-03-03 08:52:51 -0600332}
333
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700334/** @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 */
343template <int family>
344void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
345 const typename AddrFamily<family>::addr& address,
346 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530347{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700348 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}
Tom Josepha30c8d32018-03-22 02:15:03 +0530357
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700358/** @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 */
364auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530365{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700366 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
367}
Tom Josepha30c8d32018-03-22 02:15:03 +0530368
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700369/** @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 */
376void 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)
Tom Josepha30c8d32018-03-22 02:15:03 +0530382 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700383 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530384 elog<InternalFailure>();
385 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700386 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
387 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530388 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700389 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
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700396template <int family>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700397std::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
410template <int family>
411std::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
418template <int family>
419void 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
William A. Kennington III16064aa2019-04-13 17:44:53 -0700440/** @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 */
446void 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 */
464void 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 */
476IPv6Source 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 */
505void 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(static_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(static_cast<uint8_t>(status));
529}
530
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700531/** @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 */
537uint16_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));
Tom Josepha30c8d32018-03-22 02:15:03 +0530551 elog<InternalFailure>();
552 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700553 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530554}
555
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700556/** @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 */
561void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500562{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700563 // 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
Johnathan Mantey65265362019-11-14 11:24:19 -0800588 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500589}
590
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700591/** @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 */
597void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530598{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700599 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530600 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700601 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530602 }
603
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700604 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);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530611}
612
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700613/** @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 */
619void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
620 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500621{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700622 // 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.
Nan Li3d0df912016-10-18 19:51:41 +0800626
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700627 // 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);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700630 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 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800641 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700642 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
643 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700644 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500645
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700646 deconfigureChannel(bus, params);
647 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500648
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700649 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800650 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700651 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800652 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700653 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800654 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700655 for (const auto& ifaddr6 : ifaddrs6)
656 {
657 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
658 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700659 if (neighbor4)
660 {
661 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
662 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700663 if (neighbor6)
664 {
665 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
666 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700667}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800668
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700669/** @brief Turns a prefix into a netmask
670 *
671 * @param[in] prefix - The prefix length
672 * @return The netmask
673 */
674in_addr prefixToNetmask(uint8_t prefix)
675{
676 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500677 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700678 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 */
694uint8_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 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800704 return static_cast<bool>(x)
705 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
706 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700707}
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.
711static 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.
717static 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 */
725SetStatus& 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
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700735/**
736 * Define placeholder command handlers for the OEM Extension bytes for the Set
737 * LAN Configuration Parameters and Get LAN Configuration Parameters
738 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
739 * functions below to be overridden.
740 * To create handlers for your own proprietary command set:
741 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
742 * recipe
743 * Create C++ file(s) that define IPMI handler functions matching the
744 * function names below (i.e. setLanOem). The default name for the
745 * transport IPMI commands is transporthandler_oem.cpp.
746 * Add:
747 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
748 * Create a do_compile_prepend()/do_install_append method in your
749 * bbappend file to copy the file to the build directory.
750 * Add:
751 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
752 * # Copy the "strong" functions into the working directory, overriding the
753 * # placeholder functions.
754 * do_compile_prepend(){
755 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
756 * }
757 *
758 * # Clean up after complilation has completed
759 * do_install_append(){
760 * rm -f ${S}/transporthandler_oem.cpp
761 * }
762 *
763 */
764
765/**
766 * Define the placeholder OEM commands as having weak linkage. Create
767 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
768 * file. The functions defined there must not have the "weak" attribute
769 * applied to them.
770 */
771RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
772 __attribute__((weak));
773RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
774 uint8_t set, uint8_t block)
775 __attribute__((weak));
776
777RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
778{
779 req.trailingOk = true;
780 return response(ccParamNotSupported);
781}
782
783RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
784 uint8_t set, uint8_t block)
785{
786 return response(ccParamNotSupported);
787}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530788/**
789 * @brief is MAC address valid.
790 *
791 * This function checks whether the MAC address is valid or not.
792 *
793 * @param[in] mac - MAC address.
794 * @return true if MAC address is valid else retun false.
795 **/
796bool isValidMACAddress(const ether_addr& mac)
797{
798 // check if mac address is empty
799 if (equal(mac, ether_addr{}))
800 {
801 return false;
802 }
803 // we accept only unicast MAC addresses and same thing has been checked in
804 // phosphor-network layer. If the least significant bit of the first octet
805 // is set to 1, it is multicast MAC else it is unicast MAC address.
806 if (mac.ether_addr_octet[0] & 1)
807 {
808 return false;
809 }
810 return true;
811}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700812
vijayabharathix shettycc769252020-02-27 17:52:20 +0000813RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
814 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700815{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000816 const uint8_t channel = convertCurrentChannelNum(
817 static_cast<uint8_t>(channelBits), ctx->channel);
818 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700819 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000820 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700821 req.trailingOk = true;
822 return responseInvalidFieldRequest();
823 }
824
825 switch (static_cast<LanParam>(parameter))
826 {
827 case LanParam::SetStatus:
828 {
829 uint2_t flag;
830 uint6_t rsvd;
831 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
832 {
833 return responseReqDataLenInvalid();
834 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800835 if (rsvd)
836 {
837 return responseInvalidFieldRequest();
838 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700839 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
840 switch (status)
841 {
842 case SetStatus::Complete:
843 {
844 getSetStatus(channel) = status;
845 return responseSuccess();
846 }
847 case SetStatus::InProgress:
848 {
849 auto& storedStatus = getSetStatus(channel);
850 if (storedStatus == SetStatus::InProgress)
851 {
852 return response(ccParamSetLocked);
853 }
854 storedStatus = status;
855 return responseSuccess();
856 }
857 case SetStatus::Commit:
858 if (getSetStatus(channel) != SetStatus::InProgress)
859 {
860 return responseInvalidFieldRequest();
861 }
862 return responseSuccess();
863 }
864 return response(ccParamNotSupported);
865 }
866 case LanParam::AuthSupport:
867 {
868 req.trailingOk = true;
869 return response(ccParamReadOnly);
870 }
871 case LanParam::AuthEnables:
872 {
873 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800874 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700875 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800876 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600877 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800878 EthernetInterface::DHCPConf dhcp =
879 channelCall<getDHCPProperty>(channel);
880 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
881 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800882 {
883 return responseCommandNotAvailable();
884 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700885 in_addr ip;
886 std::array<uint8_t, sizeof(ip)> bytes;
887 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
888 {
889 return responseReqDataLenInvalid();
890 }
891 copyInto(ip, bytes);
892 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
893 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530894 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700895 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530896 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700897 uint4_t flag;
898 uint4_t rsvd;
899 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
900 {
901 return responseReqDataLenInvalid();
902 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800903 if (rsvd)
904 {
905 return responseInvalidFieldRequest();
906 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700907 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
908 {
909 case IPSrc::DHCP:
910 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800911 // The IPSrc IPMI command is only for IPv4
912 // management. Modifying IPv6 state is done using
913 // a completely different Set LAN Configuration
914 // subcommand.
915 channelCall<setDHCPv4Property>(
916 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700917 return responseSuccess();
918 }
919 case IPSrc::Unspecified:
920 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700921 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800922 channelCall<setDHCPv4Property>(
923 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700924 return responseSuccess();
925 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530926 case IPSrc::BIOS:
927 case IPSrc::BMC:
928 {
929 return responseInvalidFieldRequest();
930 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700931 }
932 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530933 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800934 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530935 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700936 ether_addr mac;
937 std::array<uint8_t, sizeof(mac)> bytes;
938 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530939 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700940 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530941 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700942 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530943
944 if (!isValidMACAddress(mac))
945 {
946 return responseInvalidFieldRequest();
947 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700948 channelCall<setMACProperty>(channel, mac);
949 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530950 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700951 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530952 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800953 EthernetInterface::DHCPConf dhcp =
954 channelCall<getDHCPProperty>(channel);
955 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
956 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800957 {
958 return responseCommandNotAvailable();
959 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700960 in_addr netmask;
961 std::array<uint8_t, sizeof(netmask)> bytes;
962 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530963 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700964 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530965 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700966 copyInto(netmask, bytes);
967 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
968 netmaskToPrefix(netmask));
969 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530970 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700971 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +0530972 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800973 EthernetInterface::DHCPConf dhcp =
974 channelCall<getDHCPProperty>(channel);
975 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
976 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800977 {
978 return responseCommandNotAvailable();
979 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700980 in_addr gateway;
981 std::array<uint8_t, sizeof(gateway)> bytes;
982 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
983 {
984 return responseReqDataLenInvalid();
985 }
986 copyInto(gateway, bytes);
987 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
988 return responseSuccess();
989 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700990 case LanParam::Gateway1MAC:
991 {
992 ether_addr gatewayMAC;
993 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
994 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
995 {
996 return responseReqDataLenInvalid();
997 }
998 copyInto(gatewayMAC, bytes);
999 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1000 return responseSuccess();
1001 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001002 case LanParam::VLANId:
1003 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301004 uint12_t vlanData = 0;
1005 uint3_t reserved = 0;
1006 bool vlanEnable = 0;
1007
1008 if (req.unpack(vlanData) || req.unpack(reserved) ||
1009 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001010 {
1011 return responseReqDataLenInvalid();
1012 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301013
1014 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001015 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301016 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001017 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301018
1019 uint16_t vlan = static_cast<uint16_t>(vlanData);
1020
1021 if (!vlanEnable)
1022 {
1023 lastDisabledVlan[channel] = vlan;
1024 vlan = 0;
1025 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001026 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1027 {
1028 return responseInvalidFieldRequest();
1029 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301030
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001031 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001032 return responseSuccess();
1033 }
1034 case LanParam::CiphersuiteSupport:
1035 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001036 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001037 {
1038 req.trailingOk = true;
1039 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301040 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001041 case LanParam::IPFamilyEnables:
1042 {
1043 uint8_t enables;
1044 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1045 {
1046 return responseReqDataLenInvalid();
1047 }
1048 switch (static_cast<IPFamilyEnables>(enables))
1049 {
1050 case IPFamilyEnables::DualStack:
1051 return responseSuccess();
1052 case IPFamilyEnables::IPv4Only:
1053 case IPFamilyEnables::IPv6Only:
1054 return response(ccParamNotSupported);
1055 }
1056 return response(ccParamNotSupported);
1057 }
1058 case LanParam::IPv6Status:
1059 {
1060 req.trailingOk = true;
1061 return response(ccParamReadOnly);
1062 }
1063 case LanParam::IPv6StaticAddresses:
1064 {
1065 uint8_t set;
1066 uint7_t rsvd;
1067 bool enabled;
1068 in6_addr ip;
1069 std::array<uint8_t, sizeof(ip)> ipbytes;
1070 uint8_t prefix;
1071 uint8_t status;
1072 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1073 !req.fullyUnpacked())
1074 {
1075 return responseReqDataLenInvalid();
1076 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001077 if (rsvd)
1078 {
1079 return responseInvalidFieldRequest();
1080 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001081 copyInto(ip, ipbytes);
1082 if (enabled)
1083 {
1084 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1085 }
1086 else
1087 {
1088 channelCall<deconfigureIfAddr6>(channel, set);
1089 }
1090 return responseSuccess();
1091 }
1092 case LanParam::IPv6DynamicAddresses:
1093 {
1094 req.trailingOk = true;
1095 return response(ccParamReadOnly);
1096 }
1097 case LanParam::IPv6RouterControl:
1098 {
1099 std::bitset<8> control;
1100 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1101 {
1102 return responseReqDataLenInvalid();
1103 }
1104 std::bitset<8> expected;
Johnathan Mantey65265362019-11-14 11:24:19 -08001105 EthernetInterface::DHCPConf dhcp =
1106 channelCall<getDHCPProperty>(channel);
1107 if ((dhcp == EthernetInterface::DHCPConf::both) |
1108 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001109 {
1110 expected[IPv6RouterControlFlag::Dynamic] = 1;
1111 }
1112 else
1113 {
1114 expected[IPv6RouterControlFlag::Static] = 1;
1115 }
1116 if (expected != control)
1117 {
1118 return responseInvalidFieldRequest();
1119 }
1120 return responseSuccess();
1121 }
1122 case LanParam::IPv6StaticRouter1IP:
1123 {
1124 in6_addr gateway;
1125 std::array<uint8_t, sizeof(gateway)> bytes;
1126 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1127 {
1128 return responseReqDataLenInvalid();
1129 }
1130 copyInto(gateway, bytes);
1131 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1132 return responseSuccess();
1133 }
1134 case LanParam::IPv6StaticRouter1MAC:
1135 {
1136 ether_addr mac;
1137 std::array<uint8_t, sizeof(mac)> bytes;
1138 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1139 {
1140 return responseReqDataLenInvalid();
1141 }
1142 copyInto(mac, bytes);
1143 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1144 return responseSuccess();
1145 }
1146 case LanParam::IPv6StaticRouter1PrefixLength:
1147 {
1148 uint8_t prefix;
1149 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1150 {
1151 return responseReqDataLenInvalid();
1152 }
1153 if (prefix != 0)
1154 {
1155 return responseInvalidFieldRequest();
1156 }
1157 return responseSuccess();
1158 }
1159 case LanParam::IPv6StaticRouter1PrefixValue:
1160 {
1161 std::array<uint8_t, sizeof(in6_addr)> bytes;
1162 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1163 {
1164 return responseReqDataLenInvalid();
1165 }
1166 // Accept any prefix value since our prefix length has to be 0
1167 return responseSuccess();
1168 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001169 case LanParam::cipherSuitePrivilegeLevels:
1170 {
1171 uint8_t reserved;
1172 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1173
1174 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1175 {
1176 return responseReqDataLenInvalid();
1177 }
1178
1179 if (reserved)
1180 {
1181 return responseInvalidFieldRequest();
1182 }
1183
1184 uint8_t resp =
1185 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1186 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1187 if (!resp)
1188 {
1189 return responseSuccess();
1190 }
1191 else
1192 {
1193 req.trailingOk = true;
1194 return response(resp);
1195 }
1196 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301197 }
vishwa1eaea4f2016-02-26 11:57:40 -06001198
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001199 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1200 {
1201 return setLanOem(channel, parameter, req);
1202 }
1203
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001204 req.trailingOk = true;
1205 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001206}
1207
vijayabharathix shettycc769252020-02-27 17:52:20 +00001208RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1209 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001210 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301211{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001212 message::Payload ret;
1213 constexpr uint8_t current_revision = 0x11;
1214 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001215
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001216 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301217 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001218 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301219 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001220
vijayabharathix shettycc769252020-02-27 17:52:20 +00001221 const uint8_t channel = convertCurrentChannelNum(
1222 static_cast<uint8_t>(channelBits), ctx->channel);
1223 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001224 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001225 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001226 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001227 }
1228
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001229 static std::vector<uint8_t> cipherList;
1230 static bool listInit = false;
1231 if (!listInit)
1232 {
1233 try
1234 {
1235 cipherList = cipher::getCipherList();
1236 listInit = true;
1237 }
1238 catch (const std::exception& e)
1239 {
1240 }
1241 }
1242
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001243 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301244 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001245 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301246 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001247 SetStatus status;
1248 try
1249 {
1250 status = setStatus.at(channel);
1251 }
1252 catch (const std::out_of_range&)
1253 {
1254 status = SetStatus::Complete;
1255 }
1256 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1257 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301258 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001259 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301260 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001261 std::bitset<6> support;
1262 ret.pack(support, uint2_t{});
1263 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301264 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001265 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001266 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001267 std::bitset<6> enables;
1268 ret.pack(enables, uint2_t{}); // Callback
1269 ret.pack(enables, uint2_t{}); // User
1270 ret.pack(enables, uint2_t{}); // Operator
1271 ret.pack(enables, uint2_t{}); // Admin
1272 ret.pack(enables, uint2_t{}); // OEM
1273 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001274 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001275 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001276 {
1277 auto ifaddr = channelCall<getIfAddr4>(channel);
1278 in_addr addr{};
1279 if (ifaddr)
1280 {
1281 addr = ifaddr->address;
1282 }
1283 ret.pack(dataRef(addr));
1284 return responseSuccess(std::move(ret));
1285 }
1286 case LanParam::IPSrc:
1287 {
1288 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001289 EthernetInterface::DHCPConf dhcp =
1290 channelCall<getDHCPProperty>(channel);
1291 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1292 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001293 {
1294 src = IPSrc::DHCP;
1295 }
1296 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1297 return responseSuccess(std::move(ret));
1298 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001299 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001300 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001301 ether_addr mac = channelCall<getMACProperty>(channel);
1302 ret.pack(dataRef(mac));
1303 return responseSuccess(std::move(ret));
1304 }
1305 case LanParam::SubnetMask:
1306 {
1307 auto ifaddr = channelCall<getIfAddr4>(channel);
1308 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1309 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301310 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001311 prefix = ifaddr->prefix;
1312 }
1313 in_addr netmask = prefixToNetmask(prefix);
1314 ret.pack(dataRef(netmask));
1315 return responseSuccess(std::move(ret));
1316 }
1317 case LanParam::Gateway1:
1318 {
1319 auto gateway =
1320 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1321 in_addr{});
1322 ret.pack(dataRef(gateway));
1323 return responseSuccess(std::move(ret));
1324 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001325 case LanParam::Gateway1MAC:
1326 {
1327 ether_addr mac{};
1328 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1329 if (neighbor)
1330 {
1331 mac = neighbor->mac;
1332 }
1333 ret.pack(dataRef(mac));
1334 return responseSuccess(std::move(ret));
1335 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001336 case LanParam::VLANId:
1337 {
1338 uint16_t vlan = channelCall<getVLANProperty>(channel);
1339 if (vlan != 0)
1340 {
1341 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301342 }
1343 else
1344 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001345 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301346 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001347 ret.pack(vlan);
1348 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001349 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001350 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001351 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001352 if (getChannelSessionSupport(channel) ==
1353 EChannelSessSupported::none)
1354 {
1355 return responseInvalidFieldRequest();
1356 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001357 if (!listInit)
1358 {
1359 return responseUnspecifiedError();
1360 }
1361 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1362 return responseSuccess(std::move(ret));
1363 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001364 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001365 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001366 if (getChannelSessionSupport(channel) ==
1367 EChannelSessSupported::none)
1368 {
1369 return responseInvalidFieldRequest();
1370 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001371 if (!listInit)
1372 {
1373 return responseUnspecifiedError();
1374 }
1375 ret.pack(cipherList);
1376 return responseSuccess(std::move(ret));
1377 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001378 case LanParam::IPFamilySupport:
1379 {
1380 std::bitset<8> support;
1381 support[IPFamilySupportFlag::IPv6Only] = 0;
1382 support[IPFamilySupportFlag::DualStack] = 1;
1383 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1384 ret.pack(support);
1385 return responseSuccess(std::move(ret));
1386 }
1387 case LanParam::IPFamilyEnables:
1388 {
1389 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1390 return responseSuccess(std::move(ret));
1391 }
1392 case LanParam::IPv6Status:
1393 {
1394 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1395 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1396 std::bitset<8> support;
1397 support[IPv6StatusFlag::DHCP] = 1;
1398 support[IPv6StatusFlag::SLAAC] = 1;
1399 ret.pack(support);
1400 return responseSuccess(std::move(ret));
1401 }
1402 case LanParam::IPv6StaticAddresses:
1403 {
1404 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1405 {
1406 return responseParmOutOfRange();
1407 }
1408 getLanIPv6Address(ret, channel, set, originsV6Static);
1409 return responseSuccess(std::move(ret));
1410 }
1411 case LanParam::IPv6DynamicAddresses:
1412 {
1413 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1414 {
1415 return responseParmOutOfRange();
1416 }
1417 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1418 return responseSuccess(std::move(ret));
1419 }
1420 case LanParam::IPv6RouterControl:
1421 {
1422 std::bitset<8> control;
Johnathan Mantey65265362019-11-14 11:24:19 -08001423 EthernetInterface::DHCPConf dhcp =
1424 channelCall<getDHCPProperty>(channel);
1425 if ((dhcp == EthernetInterface::DHCPConf::both) ||
1426 (dhcp == EthernetInterface::DHCPConf::v6))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001427 {
1428 control[IPv6RouterControlFlag::Dynamic] = 1;
1429 }
1430 else
1431 {
1432 control[IPv6RouterControlFlag::Static] = 1;
1433 }
1434 ret.pack(control);
1435 return responseSuccess(std::move(ret));
1436 }
1437 case LanParam::IPv6StaticRouter1IP:
1438 {
1439 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001440 EthernetInterface::DHCPConf dhcp =
1441 channelCall<getDHCPProperty>(channel);
1442 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1443 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001444 {
1445 gateway =
1446 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1447 in6_addr{});
1448 }
1449 ret.pack(dataRef(gateway));
1450 return responseSuccess(std::move(ret));
1451 }
1452 case LanParam::IPv6StaticRouter1MAC:
1453 {
1454 ether_addr mac{};
1455 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1456 if (neighbor)
1457 {
1458 mac = neighbor->mac;
1459 }
1460 ret.pack(dataRef(mac));
1461 return responseSuccess(std::move(ret));
1462 }
1463 case LanParam::IPv6StaticRouter1PrefixLength:
1464 {
1465 ret.pack(UINT8_C(0));
1466 return responseSuccess(std::move(ret));
1467 }
1468 case LanParam::IPv6StaticRouter1PrefixValue:
1469 {
1470 in6_addr prefix{};
1471 ret.pack(dataRef(prefix));
1472 return responseSuccess(std::move(ret));
1473 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001474 case LanParam::cipherSuitePrivilegeLevels:
1475 {
1476 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1477
1478 uint8_t resp =
1479 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1480 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1481 if (!resp)
1482 {
1483 constexpr uint8_t reserved1 = 0x00;
1484 ret.pack(reserved1, csPrivilegeLevels);
1485 return responseSuccess(std::move(ret));
1486 }
1487 else
1488 {
1489 return response(resp);
1490 }
1491 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001492 }
1493
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001494 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1495 {
1496 return getLanOem(channel, parameter, set, block);
1497 }
1498
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001499 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001500}
1501
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001502} // namespace transport
1503} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301504
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001505void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301506
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001507void register_netfn_transport_functions()
1508{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001509 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1510 ipmi::transport::cmdSetLanConfigParameters,
1511 ipmi::Privilege::Admin, ipmi::transport::setLan);
1512 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1513 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001514 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001515}