xref: /openbmc/slpd-lite/slp_parser.cpp (revision 0e948dca)
1 #include "endian.hpp"
2 #include "slp.hpp"
3 #include "slp_meta.hpp"
4 
5 #include <string.h>
6 
7 #include <algorithm>
8 #include <string>
9 
10 namespace slp
11 {
12 
13 namespace parser
14 {
15 
16 namespace internal
17 {
18 
19 std::tuple<int, Message> parseHeader(const buffer& buff)
20 {
21     /*  0                   1                   2                   3
22         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
23        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24        |    Version    |  Function-ID  |            Length             |
25        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26        | Length, contd.|O|F|R|       reserved          |Next Ext Offset|
27        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28        |  Next Extension Offset, contd.|              XID              |
29        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30        |      Language Tag Length      |         Language Tag          \
31        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
32 
33     Message req{};
34     int rc = slp::SUCCESS;
35 
36     if (buff.size() < slp::header::MIN_LEN)
37     {
38         std::cerr << "Invalid msg size: " << buff.size() << std::endl;
39         rc = static_cast<int>(slp::Error::PARSE_ERROR);
40     }
41     else
42     {
43         std::copy_n(buff.data(), slp::header::SIZE_VERSION,
44                     &req.header.version);
45 
46         std::copy_n(buff.data() + slp::header::OFFSET_FUNCTION,
47                     slp::header::SIZE_VERSION, &req.header.functionID);
48 
49         std::copy_n(buff.data() + slp::header::OFFSET_LENGTH,
50                     slp::header::SIZE_LENGTH, req.header.length.data());
51 
52         std::copy_n(buff.data() + slp::header::OFFSET_FLAGS,
53                     slp::header::SIZE_FLAGS, (uint8_t*)&req.header.flags);
54 
55         req.header.flags = endian::from_network(req.header.flags);
56         std::copy_n(buff.data() + slp::header::OFFSET_EXT,
57                     slp::header::SIZE_EXT, req.header.extOffset.data());
58 
59         std::copy_n(buff.data() + slp::header::OFFSET_XID,
60                     slp::header::SIZE_XID, (uint8_t*)&req.header.xid);
61 
62         req.header.xid = endian::from_network(req.header.xid);
63 
64         uint16_t langtagLen;
65 
66         std::copy_n(buff.data() + slp::header::OFFSET_LANG_LEN,
67                     slp::header::SIZE_LANG, (uint8_t*)&langtagLen);
68 
69         langtagLen = endian::from_network(langtagLen);
70 
71         req.header.langtag.insert(
72             0, (const char*)buff.data() + slp::header::OFFSET_LANG, langtagLen);
73 
74         /* check for the validity of the function */
75         if (req.header.functionID <
76                 static_cast<uint8_t>(slp::FunctionType::SRVRQST) ||
77             req.header.functionID >
78                 static_cast<uint8_t>(slp::FunctionType::SAADV))
79         {
80             std::cerr << "Invalid function ID: " << req.header.functionID
81                       << std::endl;
82             rc = static_cast<int>(slp::Error::PARSE_ERROR);
83         }
84     }
85 
86     return std::make_tuple(rc, std::move(req));
87 }
88 
89 int parseSrvTypeRqst(const buffer& buff, Message& req)
90 {
91     /*  0                   1                   2                   3
92         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
93        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94        |        length of PRList       |        <PRList> String        \
95        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96        |   length of Naming Authority  |   <Naming Authority String>   \
97        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98        |     length of <scope-list>    |      <scope-list> String      \
99        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
100 
101     /* Enforce SLPv2 service type request size limits. */
102     if (buff.size() < slp::request::MIN_SRVTYPE_LEN)
103     {
104         return (int)slp::Error::PARSE_ERROR;
105     }
106 
107     /* Parse the PRList. */
108     uint16_t prListLen;
109     std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
110                 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen);
111 
112     prListLen = endian::from_network(prListLen);
113 
114     req.body.srvtyperqst.prList.insert(
115         0, (const char*)buff.data() + slp::request::OFFSET_PR, prListLen);
116 
117     uint8_t pos = slp::request::OFFSET_PR + prListLen;
118 
119     /* Parse the Naming Authority. */
120     uint16_t namingAuthLen;
121     std::copy_n(buff.data() + pos, slp::request::SIZE_NAMING,
122                 (uint8_t*)&namingAuthLen);
123 
124     pos += slp::request::SIZE_NAMING;
125 
126     namingAuthLen = endian::from_network(namingAuthLen);
127 
128     if (namingAuthLen == 0 || namingAuthLen == 0xffff)
129     {
130         req.body.srvtyperqst.namingAuth = "";
131     }
132     else
133     {
134         req.body.srvtyperqst.namingAuth.insert(
135             0, (const char*)buff.data() + pos, namingAuthLen);
136     }
137 
138     pos += namingAuthLen;
139 
140     /* Parse the <scope-list>. */
141     uint16_t scopeListLen;
142     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
143                 (uint8_t*)&scopeListLen);
144 
145     pos += slp::request::SIZE_SCOPE;
146 
147     scopeListLen = endian::from_network(scopeListLen);
148 
149     req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos,
150                                           scopeListLen);
151 
152     return slp::SUCCESS;
153 }
154 
155 int parseSrvRqst(const buffer& buff, Message& req)
156 {
157     /*  0                   1                   2                   3
158         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
159        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160        |      length of <PRList>       |        <PRList> String        \
161        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162        |   length of <service-type>    |    <service-type> String      \
163        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164        |    length of <scope-list>     |     <scope-list> String       \
165        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
166        |  length of predicate string   |  Service Request <predicate>  \
167        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
168        |  length of <SLP SPI> string   |       <SLP SPI> String        \
169        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
170 
171     /* Enforce v2 service request size limits. */
172     if (buff.size() < slp::request::MIN_SRV_LEN)
173     {
174         return (int)slp::Error::PARSE_ERROR;
175     }
176 
177     /* 1) Parse the PRList. */
178     uint16_t prListLen;
179     std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
180                 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen);
181 
182     auto pos = slp::request::OFFSET_PR_LEN + slp::request::SIZE_PRLIST;
183 
184     prListLen = endian::from_network(prListLen);
185 
186     req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos,
187                                    prListLen);
188 
189     pos += prListLen;
190 
191     /* 2) Parse the <service-type> string. */
192     uint16_t srvTypeLen;
193     std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE,
194                 (uint8_t*)&srvTypeLen);
195 
196     srvTypeLen = endian::from_network(srvTypeLen);
197 
198     pos += slp::request::SIZE_SERVICE_TYPE;
199 
200     req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos,
201                                     srvTypeLen);
202 
203     pos += srvTypeLen;
204 
205     /* 3) Parse the <scope-list> string. */
206     uint16_t scopeListLen;
207     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
208                 (uint8_t*)&scopeListLen);
209 
210     scopeListLen = endian::from_network(scopeListLen);
211 
212     pos += slp::request::SIZE_SCOPE;
213 
214     req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos,
215                                       scopeListLen);
216 
217     pos += scopeListLen;
218 
219     /* 4) Parse the <predicate> string. */
220     uint16_t predicateLen;
221     std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE,
222                 (uint8_t*)&predicateLen);
223 
224     predicateLen = endian::from_network(predicateLen);
225     pos += slp::request::SIZE_PREDICATE;
226 
227     req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos,
228                                       predicateLen);
229 
230     pos += predicateLen;
231 
232     /* 5) Parse the <SLP SPI> string. */
233     uint16_t spistrLen;
234     std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI,
235                 (uint8_t*)&spistrLen);
236 
237     spistrLen = endian::from_network(spistrLen);
238     pos += slp::request::SIZE_SLPI;
239 
240     req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos,
241                                    spistrLen);
242 
243     return slp::SUCCESS;
244 }
245 } // namespace internal
246 
247 std::tuple<int, Message> parseBuffer(const buffer& buff)
248 {
249     Message req;
250     int rc = slp::SUCCESS;
251     /* parse the header first */
252     std::tie(rc, req) = internal::parseHeader(buff);
253     if (!rc)
254     {
255         /* switch on the function id to parse the body */
256         switch (req.header.functionID)
257         {
258             case (uint8_t)slp::FunctionType::SRVTYPERQST:
259                 rc = internal::parseSrvTypeRqst(buff, req);
260                 break;
261             case (uint8_t)slp::FunctionType::SRVRQST:
262                 rc = internal::parseSrvRqst(buff, req);
263                 break;
264             default:
265                 rc = (int)slp::Error::MSG_NOT_SUPPORTED;
266         }
267     }
268     return std::make_tuple(rc, std::move(req));
269 }
270 } // namespace parser
271 } // namespace slp
272