blob: 64cc6e93c99884cccbf1f62e336de681c4ea50db [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
2#include "types.hpp"
3#include "transporthandler.hpp"
4#include "utils.hpp"
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08005#include "net.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07006
7#include <string>
8#include <arpa/inet.h>
9
10#include <phosphor-logging/log.hpp>
11#include <phosphor-logging/elog-errors.hpp>
12#include "xyz/openbmc_project/Common/error.hpp"
13
Patrick Venture5794fcf2017-10-26 11:11:14 -070014constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
15
16using namespace phosphor::logging;
17using namespace sdbusplus::xyz::openbmc_project::Common::Error;
18
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080019/** @struct SetChannelAccessRequest
20 *
21 * IPMI payload for Set Channel access command request.
22 */
23struct SetChannelAccessRequest
24{
25 uint8_t channelNumber; //!< Channel number.
26 uint8_t setting; //!< The setting values.
27 uint8_t privilegeLevelLimit; //!< The Privilege Level Limit
28} __attribute__((packed));
29
Patrick Venture5794fcf2017-10-26 11:11:14 -070030/** @struct GetChannelAccessRequest
31 *
32 * IPMI payload for Get Channel access command request.
33 */
34struct GetChannelAccessRequest
35{
36 uint8_t channelNumber; //!< Channel number.
37 uint8_t volatileSetting; //!< Get non-volatile or the volatile setting.
38} __attribute__((packed));
39
40/** @struct GetChannelAccessResponse
41 *
42 * IPMI payload for Get Channel access command response.
43 */
44struct GetChannelAccessResponse
45{
46 uint8_t settings; //!< Channel settings.
47 uint8_t privilegeLimit; //!< Channel privilege level limit.
48} __attribute__((packed));
49
50ipmi_ret_t ipmi_set_channel_access(ipmi_netfn_t netfn,
51 ipmi_cmd_t cmd,
52 ipmi_request_t request,
53 ipmi_response_t response,
54 ipmi_data_len_t data_len,
55 ipmi_context_t context)
56{
57 ipmi_ret_t rc = IPMI_CC_OK;
58
59 std::string ipaddress;
60 std::string gateway;
61 uint8_t prefix {};
62 uint32_t vlanID {};
63 std::string networkInterfacePath;
64 ipmi::DbusObjectInfo ipObject;
65 ipmi::DbusObjectInfo systemObject;
66
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080067 if (*data_len < sizeof(SetChannelAccessRequest))
68 {
69 return IPMI_CC_INVALID;
70 }
71
72 auto requestData = reinterpret_cast<const SetChannelAccessRequest*>
73 (request);
74 int channel = requestData->channelNumber & CHANNEL_MASK;
75 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
76 if (ethdevice.empty())
77 {
78 return IPMI_CC_INVALID_FIELD_REQUEST;
79 }
80 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
81 auto channelConf = getChannelConfig(channel);
82
Patrick Venture5794fcf2017-10-26 11:11:14 -070083 // Todo: parse the request data if needed.
84 // Using Set Channel cmd to apply changes of Set Lan Cmd.
85 try
86 {
87 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
88
89 log<level::INFO>("Network data from Cache",
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080090 entry("PREFIX=%s", channelConf->netmask.c_str()),
91 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
92 entry("GATEWAY=%s", channelConf->gateway.c_str()),
93 entry("VLAN=%d", channelConf->vlanID),
94 entry("IPSRC=%d", channelConf->ipsrc));
Patrick Venture5794fcf2017-10-26 11:11:14 -070095
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080096 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
Patrick Venture5794fcf2017-10-26 11:11:14 -070097 {
98 //get the first twelve bits which is vlan id
99 //not interested in rest of the bits.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800100 channelConf->vlanID = le32toh(channelConf->vlanID);
101 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
Patrick Venture5794fcf2017-10-26 11:11:14 -0700102 }
103
104 // if the asked ip src is DHCP then not interested in
105 // any given data except vlan.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800106 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
Patrick Venture5794fcf2017-10-26 11:11:14 -0700107 {
108 // always get the system object
109 systemObject = ipmi::getDbusObject(
110 bus,
111 ipmi::network::SYSTEMCONFIG_INTERFACE,
112 ipmi::network::ROOT);
113
114 // the below code is to determine the mode of the interface
115 // as the handling is same, if the system is configured with
116 // DHCP or user has given all the data.
117 try
118 {
119 ipmi::ObjectTree ancestorMap;
120
121 ipmi::InterfaceList interfaces {
122 ipmi::network::ETHERNET_INTERFACE };
123
124 // if the system is having ip object,then
125 // get the IP object.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800126 ipObject = ipmi::getDbusObject(bus,
127 ipmi::network::IP_INTERFACE,
128 ipmi::network::ROOT,
129 ethIp);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700130
131 // Get the parent interface of the IP object.
132 try
133 {
134 ancestorMap = ipmi::getAllAncestors(bus,
135 ipObject.first,
136 std::move(interfaces));
137 }
138 catch (InternalFailure& e)
139 {
140 // if unable to get the parent interface
141 // then commit the error and return.
142 log<level::ERR>("Unable to get the parent interface",
143 entry("PATH=%s", ipObject.first.c_str()),
144 entry("INTERFACE=%s",
145 ipmi::network::ETHERNET_INTERFACE));
146 commit<InternalFailure>();
147 rc = IPMI_CC_UNSPECIFIED_ERROR;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800148 channelConf->clear();
Patrick Venture5794fcf2017-10-26 11:11:14 -0700149 return rc;
150 }
151
152 networkInterfacePath = ancestorMap.begin()->first;
153 }
154 catch (InternalFailure& e)
155 {
156 // TODO Currently IPMI supports single interface,need to handle
157 // Multiple interface through
158 // https://github.com/openbmc/openbmc/issues/2138
159
160 // if there is no ip configured on the system,then
161 // get the network interface object.
162 auto networkInterfaceObject = ipmi::getDbusObject(
163 bus,
164 ipmi::network::ETHERNET_INTERFACE,
165 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800166 ethdevice);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700167
168 networkInterfacePath = std::move(networkInterfaceObject.first);
169 }
170
171 // get the configured mode on the system.
172 auto enableDHCP = ipmi::getDbusProperty(
173 bus,
174 ipmi::network::SERVICE,
175 networkInterfacePath,
176 ipmi::network::ETHERNET_INTERFACE,
177 "DHCPEnabled").get<bool>();
178
179 // check whether user has given all the data
180 // or the configured system interface is dhcp enabled,
181 // in both of the cases get the values from the cache.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800182 if ((!channelConf->ipaddr.empty() &&
183 !channelConf->netmask.empty() &&
184 !channelConf->gateway.empty()) ||
Patrick Venture5794fcf2017-10-26 11:11:14 -0700185 (enableDHCP)) // configured system interface mode = DHCP
186 {
187 //convert mask into prefix
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800188 ipaddress = channelConf->ipaddr;
189 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
190 gateway = channelConf->gateway;
191 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
Patrick Venture5794fcf2017-10-26 11:11:14 -0700192 {
193 //get the first twelve bits which is vlan id
194 //not interested in rest of the bits.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800195 channelConf->vlanID = le32toh(channelConf->vlanID);
196 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
Patrick Venture5794fcf2017-10-26 11:11:14 -0700197 }
198 else
199 {
200 vlanID = ipmi::network::getVLAN(networkInterfacePath);
201 }
202
203 }
204 else // asked ip src = static and configured system src = static
205 // or partially given data.
206 {
207 // We have partial filled cache so get the remaining
208 // info from the system.
209
210 // Get the network data from the system as user has
211 // not given all the data then use the data fetched from the
212 // system but it is implementation dependent,IPMI spec doesn't
213 // force it.
214
215 // if system is not having any ip object don't throw error,
216 try
217 {
218 auto properties = ipmi::getAllDbusProperties(
219 bus,
220 ipObject.second,
221 ipObject.first,
222 ipmi::network::IP_INTERFACE);
223
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800224 ipaddress = channelConf->ipaddr.empty() ?
Ratan Guptadd646202017-11-21 17:46:59 +0530225 properties["Address"].get<std::string>() :
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800226 channelConf->ipaddr;
Patrick Venture5794fcf2017-10-26 11:11:14 -0700227
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800228 prefix = channelConf->netmask.empty() ?
Patrick Venture5794fcf2017-10-26 11:11:14 -0700229 properties["PrefixLength"].get<uint8_t>() :
230 ipmi::network::toPrefix(AF_INET,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800231 channelConf->netmask);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700232 }
233 catch (InternalFailure& e)
234 {
235 log<level::INFO>("Failed to get IP object which matches",
236 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800237 entry("MATCH=%s", ethIp));
Patrick Venture5794fcf2017-10-26 11:11:14 -0700238 }
239
240 auto systemProperties = ipmi::getAllDbusProperties(
241 bus,
242 systemObject.second,
243 systemObject.first,
244 ipmi::network::SYSTEMCONFIG_INTERFACE);
245
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800246 gateway = channelConf->gateway.empty() ?
Patrick Venture5794fcf2017-10-26 11:11:14 -0700247 systemProperties["DefaultGateway"].get<std::string>() :
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800248 channelConf->gateway;
Patrick Venture5794fcf2017-10-26 11:11:14 -0700249 }
250 }
251
252 // Currently network manager doesn't support purging of all the
253 // ip addresses and the vlan interfaces from the parent interface,
254 // TODO once the support is there, will make the change here.
255 // https://github.com/openbmc/openbmc/issues/2141.
256
257 // TODO Currently IPMI supports single interface,need to handle
258 // Multiple interface through
259 // https://github.com/openbmc/openbmc/issues/2138
260
261 // instead of deleting all the vlan interfaces and
262 // all the ipv4 address,we will call reset method.
263 //delete all the vlan interfaces
264
265 ipmi::deleteAllDbusObjects(bus,
266 ipmi::network::ROOT,
267 ipmi::network::VLAN_INTERFACE);
268
269 // set the interface mode to static
270 auto networkInterfaceObject = ipmi::getDbusObject(
271 bus,
272 ipmi::network::ETHERNET_INTERFACE,
273 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800274 ethdevice);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700275
276 // setting the physical interface mode to static.
277 ipmi::setDbusProperty(bus,
278 ipmi::network::SERVICE,
279 networkInterfaceObject.first,
280 ipmi::network::ETHERNET_INTERFACE,
281 "DHCPEnabled",
282 false);
283
284 networkInterfacePath = networkInterfaceObject.first;
285
286 //delete all the ipv4 addresses
287 ipmi::deleteAllDbusObjects(bus,
288 ipmi::network::ROOT,
289 ipmi::network::IP_INTERFACE,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800290 ethIp);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700291
292 if (vlanID)
293 {
294 ipmi::network::createVLAN(bus,
295 ipmi::network::SERVICE,
296 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800297 ethdevice,
Patrick Venture5794fcf2017-10-26 11:11:14 -0700298 vlanID);
299
300 auto networkInterfaceObject = ipmi::getDbusObject(
301 bus,
302 ipmi::network::VLAN_INTERFACE,
303 ipmi::network::ROOT);
304
305 networkInterfacePath = networkInterfaceObject.first;
306 }
307
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800308 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
Patrick Venture5794fcf2017-10-26 11:11:14 -0700309 {
310 ipmi::setDbusProperty(bus,
311 ipmi::network::SERVICE,
312 networkInterfacePath,
313 ipmi::network::ETHERNET_INTERFACE,
314 "DHCPEnabled",
315 true);
316 }
317 else
318 {
319 //change the mode to static
320 ipmi::setDbusProperty(bus,
321 ipmi::network::SERVICE,
322 networkInterfacePath,
323 ipmi::network::ETHERNET_INTERFACE,
324 "DHCPEnabled",
325 false);
326
327 if (!ipaddress.empty())
328 {
329 ipmi::network::createIP(bus,
330 ipmi::network::SERVICE,
331 networkInterfacePath,
332 ipv4Protocol,
333 ipaddress,
334 prefix);
335 }
336
337 if (!gateway.empty())
338 {
339 ipmi::setDbusProperty(bus,
340 systemObject.second,
341 systemObject.first,
342 ipmi::network::SYSTEMCONFIG_INTERFACE,
343 "DefaultGateway",
344 std::string(gateway));
345 }
346 }
347
348 }
349 catch (InternalFailure& e)
350 {
351 log<level::ERR>("Failed to set network data",
352 entry("PREFIX=%d", prefix),
353 entry("ADDRESS=%s", ipaddress.c_str()),
354 entry("GATEWAY=%s", gateway.c_str()),
355 entry("VLANID=%d", vlanID),
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800356 entry("IPSRC=%d", channelConf->ipsrc));
Patrick Venture5794fcf2017-10-26 11:11:14 -0700357
358 commit<InternalFailure>();
359 rc = IPMI_CC_UNSPECIFIED_ERROR;
360 }
361
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800362 channelConf->clear();
Patrick Venture5794fcf2017-10-26 11:11:14 -0700363 return rc;
364}
365
366ipmi_ret_t ipmi_get_channel_access(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
367 ipmi_request_t request, ipmi_response_t response,
368 ipmi_data_len_t data_len, ipmi_context_t context)
369{
370 auto requestData = reinterpret_cast<const GetChannelAccessRequest*>
371 (request);
372 std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
373 auto responseData = reinterpret_cast<GetChannelAccessResponse*>
374 (outPayload.data());
375
Patrick Venture5794fcf2017-10-26 11:11:14 -0700376 /*
377 * The value Eh is used as a way to identify the current channel that
378 * the command is being received from.
379 */
380 constexpr auto channelE = 0x0E;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800381 int channel = requestData->channelNumber;
382 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700383
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800384 if (channel != channelE && ethdevice.empty())
Patrick Venture5794fcf2017-10-26 11:11:14 -0700385 {
386 *data_len = 0;
387 return IPMI_CC_INVALID_FIELD_REQUEST;
388 }
389
390 /*
391 * [7:6] - reserved
392 * [5] - 1b = Alerting disabled
393 * [4] - 1b = per message authentication disabled
394 * [3] - 0b = User level authentication enabled
395 * [2:0] - 2h = always available
396 */
397 constexpr auto channelSetting = 0x32;
398
399 responseData->settings = channelSetting;
400 //Defaulting the channel privilege to administrator level.
401 responseData->privilegeLimit = PRIVILEGE_ADMIN;
402
403 *data_len = outPayload.size();
404 memcpy(response, outPayload.data(), *data_len);
405
406 return IPMI_CC_OK;
407}
408
409// ATTENTION: This ipmi function is very hardcoded on purpose
410// OpenBMC does not fully support IPMI. This command is useful
411// to have around because it enables testing of interfaces with
412// the IPMI tool.
413#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
414// IPMI Table 6-2
415#define IPMI_CHANNEL_TYPE_IPMB 1
416// IPMI Table 6-3
417#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
418
419ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
420 ipmi_request_t request, ipmi_response_t response,
421 ipmi_data_len_t data_len, ipmi_context_t context)
422{
423 ipmi_ret_t rc = IPMI_CC_OK;
424 uint8_t resp[] = {
425 1,
426 IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
427 IPMI_CHANNEL_TYPE_IPMB,
428 1,0x41,0xA7,0x00,0,0};
429 uint8_t *p = (uint8_t*) request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800430 int channel = (*p) & CHANNEL_MASK;
431 std::string ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700432
433 printf("IPMI APP GET CHANNEL INFO\n");
434
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800435 // The supported channels numbers are those which are configured.
Patrick Venture5794fcf2017-10-26 11:11:14 -0700436 // Channel Number E is used as way to identify the current channel
437 // that the command is being is received from.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800438 if (channel != 0xe && ethdevice.empty()) {
Patrick Venture5794fcf2017-10-26 11:11:14 -0700439 rc = IPMI_CC_PARM_OUT_OF_RANGE;
440 *data_len = 0;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800441 } else {
442 *data_len = sizeof(resp);
443 memcpy(response, resp, *data_len);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700444 }
445
446 return rc;
447}