xref: /openbmc/pldm/common/transport.cpp (revision e7ae804d00ea1dc55741b03d15b5ffa101e14687)
1 #include "common/transport.hpp"
2 
3 #include <libpldm/transport.h>
4 #include <libpldm/transport/af-mctp.h>
5 #include <libpldm/transport/mctp-demux.h>
6 
7 #include <algorithm>
8 #include <ranges>
9 #include <system_error>
10 
11 struct pldm_transport* transport_impl_init(TransportImpl& impl, pollfd& pollfd,
12                                            bool listening);
13 void transport_impl_destroy(TransportImpl& impl);
14 
15 static constexpr uint8_t MCTP_EID_VALID_MIN = 8;
16 static constexpr uint8_t MCTP_EID_VALID_MAX = 255;
17 
18 /*
19  * Currently the OpenBMC ecosystem assumes TID == EID. Pre-populate the TID
20  * mappings over the EID space excluding the Null (0), Reserved (1 to 7),
21  * Broadcast EIDs (255) defined by Section 8.2 Special endpoint IDs in DSP0236
22  * v1.3.1. Further, by Section 8.1.1 SetTID command (0x01) in DSP0240 v1.1.0,
23  * the TIDs 0x00 and 0xff are also reserved. These overlap with the reserved
24  * EIDs so no additional filtering is required.
25  *
26  * Further, pldmtool and pldmd are two separate processes. They are opening two
27  * different sockets, but with the mctp-demux-daemon, the response messages are
28  * broadcasted to all sockets. When pldmd receives the response for a request
29  * issued by pldmtool, pldm_transport_mctp_demux_recv() may return with error
30  * PLDM_REQUESTER_RECV_FAIL if it fails to map the EID of the source endpoint to
31  * its TID. The EID to TID mappings of pldmtool and pldmd should be coherent to
32  * prevent the failure of pldm_transport_mctp_demux_recv().
33  */
34 
35 [[maybe_unused]] static struct pldm_transport*
pldm_transport_impl_mctp_demux_init(TransportImpl & impl,pollfd & pollfd)36     pldm_transport_impl_mctp_demux_init(TransportImpl& impl, pollfd& pollfd)
37 {
38     impl.mctp_demux = nullptr;
39     pldm_transport_mctp_demux_init(&impl.mctp_demux);
40     if (!impl.mctp_demux)
41     {
42         return nullptr;
43     }
44 
45     for (const auto eid :
46          std::views::iota(MCTP_EID_VALID_MIN, MCTP_EID_VALID_MAX))
47     {
48         int rc = pldm_transport_mctp_demux_map_tid(impl.mctp_demux, eid, eid);
49         if (rc)
50         {
51             pldm_transport_af_mctp_destroy(impl.af_mctp);
52             return nullptr;
53         }
54     }
55 
56     pldm_transport* pldmTransport =
57         pldm_transport_mctp_demux_core(impl.mctp_demux);
58 
59     if (pldmTransport != nullptr)
60     {
61         pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd);
62     }
63 
64     return pldmTransport;
65 }
66 
pldm_transport_impl_af_mctp_init(TransportImpl & impl,pollfd & pollfd,bool listening)67 [[maybe_unused]] static struct pldm_transport* pldm_transport_impl_af_mctp_init(
68     TransportImpl& impl, pollfd& pollfd, bool listening)
69 {
70     impl.af_mctp = nullptr;
71     pldm_transport_af_mctp_init(&impl.af_mctp);
72     if (!impl.af_mctp)
73     {
74         return nullptr;
75     }
76 
77     for (const auto eid :
78          std::views::iota(MCTP_EID_VALID_MIN, MCTP_EID_VALID_MAX))
79     {
80         int rc = pldm_transport_af_mctp_map_tid(impl.af_mctp, eid, eid);
81         if (rc)
82         {
83             pldm_transport_af_mctp_destroy(impl.af_mctp);
84             return nullptr;
85         }
86     }
87 
88     /* Listen for requests on any interface */
89     if (listening && pldm_transport_af_mctp_bind(impl.af_mctp, nullptr, 0))
90     {
91         return nullptr;
92     }
93 
94     pldm_transport* pldmTransport = pldm_transport_af_mctp_core(impl.af_mctp);
95 
96     if (pldmTransport != nullptr)
97     {
98         pldm_transport_af_mctp_init_pollfd(pldmTransport, &pollfd);
99     }
100 
101     return pldmTransport;
102 }
103 
transport_impl_init(TransportImpl & impl,pollfd & pollfd,bool listening)104 struct pldm_transport* transport_impl_init(TransportImpl& impl, pollfd& pollfd,
105                                            [[maybe_unused]] bool listening)
106 {
107 #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
108     return pldm_transport_impl_mctp_demux_init(impl, pollfd);
109 #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
110     return pldm_transport_impl_af_mctp_init(impl, pollfd, listening);
111 #else
112     return nullptr;
113 #endif
114 }
115 
transport_impl_destroy(TransportImpl & impl)116 void transport_impl_destroy(TransportImpl& impl)
117 {
118 #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
119     pldm_transport_mctp_demux_destroy(impl.mctp_demux);
120 #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
121     pldm_transport_af_mctp_destroy(impl.af_mctp);
122 #endif
123 }
124 
PldmTransport(bool listening)125 PldmTransport::PldmTransport(bool listening)
126 {
127     transport = transport_impl_init(impl, pfd, listening);
128     if (!transport)
129     {
130         throw std::system_error(ENOMEM, std::generic_category());
131     }
132 }
133 
~PldmTransport()134 PldmTransport::~PldmTransport()
135 {
136     transport_impl_destroy(impl);
137 }
138 
getEventSource() const139 int PldmTransport::getEventSource() const
140 {
141     return pfd.fd;
142 }
143 
sendMsg(pldm_tid_t tid,const void * tx,size_t len)144 pldm_requester_rc_t PldmTransport::sendMsg(pldm_tid_t tid, const void* tx,
145                                            size_t len)
146 {
147     return pldm_transport_send_msg(transport, tid, tx, len);
148 }
149 
recvMsg(pldm_tid_t & tid,void * & rx,size_t & len)150 pldm_requester_rc_t PldmTransport::recvMsg(pldm_tid_t& tid, void*& rx,
151                                            size_t& len)
152 {
153     return pldm_transport_recv_msg(transport, &tid, (void**)&rx, &len);
154 }
155 
sendRecvMsg(pldm_tid_t tid,const void * tx,size_t txLen,void * & rx,size_t & rxLen)156 pldm_requester_rc_t PldmTransport::sendRecvMsg(
157     pldm_tid_t tid, const void* tx, size_t txLen, void*& rx, size_t& rxLen)
158 {
159     return pldm_transport_send_recv_msg(transport, tid, tx, txLen, &rx, &rxLen);
160 }
161