xref: /openbmc/slpd-lite/slp_parser.cpp (revision 20bab748)
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 
parseHeader(const buffer & buff)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         // Enforce language tag size limits
72         if ((slp::header::OFFSET_LANG + langtagLen) > buff.size())
73         {
74             std::cerr << "Invalid Language Tag Length: " << langtagLen
75                       << std::endl;
76             rc = static_cast<int>(slp::Error::PARSE_ERROR);
77         }
78         else
79         {
80             req.header.langtagLen = langtagLen;
81             req.header.langtag.insert(
82                 0, (const char*)buff.data() + slp::header::OFFSET_LANG,
83                 langtagLen);
84 
85             /* check for the validity of the function */
86             if (req.header.functionID <
87                     static_cast<uint8_t>(slp::FunctionType::SRVRQST) ||
88                 req.header.functionID >
89                     static_cast<uint8_t>(slp::FunctionType::SAADV))
90             {
91                 std::cerr << "Invalid function ID: " << req.header.functionID
92                           << std::endl;
93                 rc = static_cast<int>(slp::Error::PARSE_ERROR);
94             }
95         }
96     }
97 
98     return std::make_tuple(rc, std::move(req));
99 }
100 
parseSrvTypeRqst(const buffer & buff,Message & req)101 int parseSrvTypeRqst(const buffer& buff, Message& req)
102 {
103     /*  0                   1                   2                   3
104         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
105        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106        |        length of PRList       |        <PRList> String        \
107        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108        |   length of Naming Authority  |   <Naming Authority String>   \
109        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110        |     length of <scope-list>    |      <scope-list> String      \
111        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
112 
113     /* Enforce SLPv2 service type request size limits. */
114     if (buff.size() < slp::request::MIN_SRVTYPE_LEN)
115     {
116         return (int)slp::Error::PARSE_ERROR;
117     }
118 
119     /* Parse the PRList. */
120     uint16_t prListLen;
121     uint32_t pos = slp::header::MIN_LEN + req.header.langtagLen;
122     if ((pos + slp::request::SIZE_PRLIST) > buff.size())
123     {
124         std::cerr << "PRList length field is greater than input buffer: "
125                   << (pos + slp::request::SIZE_PRLIST) << " / " << buff.size()
126                   << std::endl;
127         return (int)slp::Error::PARSE_ERROR;
128     }
129     std::copy_n(buff.data() + pos, slp::request::SIZE_PRLIST,
130                 (uint8_t*)&prListLen);
131 
132     pos += slp::request::SIZE_PRLIST;
133     prListLen = endian::from_network(prListLen);
134 
135     if ((pos + prListLen) > buff.size())
136     {
137         std::cerr << "Length of PRList is greater than input buffer: "
138                   << (slp::request::OFFSET_PR + prListLen) << " / "
139                   << buff.size() << std::endl;
140         return (int)slp::Error::PARSE_ERROR;
141     }
142 
143     req.body.srvtyperqst.prList.insert(0, (const char*)buff.data() + pos,
144                                        prListLen);
145 
146     pos += prListLen;
147 
148     /* Parse the Naming Authority. */
149     uint16_t namingAuthLen;
150     if ((pos + slp::request::SIZE_NAMING) > buff.size())
151     {
152         std::cerr << "Naming auth length field is greater than input buffer: "
153                   << (pos + slp::request::SIZE_NAMING) << " / " << buff.size()
154                   << std::endl;
155         return (int)slp::Error::PARSE_ERROR;
156     }
157     std::copy_n(buff.data() + pos, slp::request::SIZE_NAMING,
158                 (uint8_t*)&namingAuthLen);
159 
160     pos += slp::request::SIZE_NAMING;
161 
162     namingAuthLen = endian::from_network(namingAuthLen);
163     if (namingAuthLen == 0 || namingAuthLen == 0xffff)
164     {
165         req.body.srvtyperqst.namingAuth = "";
166         // If it's the special 0xffff, treat like 0 size
167         namingAuthLen = 0;
168     }
169     else
170     {
171         if ((pos + namingAuthLen) > buff.size())
172         {
173             std::cerr << "Length of Naming Size is greater than input buffer: "
174                       << (pos + namingAuthLen) << " / " << buff.size()
175                       << std::endl;
176             return (int)slp::Error::PARSE_ERROR;
177         }
178         req.body.srvtyperqst.namingAuth.insert(
179             0, (const char*)buff.data() + pos, namingAuthLen);
180     }
181 
182     pos += namingAuthLen;
183 
184     /* Parse the <scope-list>. */
185     uint16_t scopeListLen;
186     if ((pos + slp::request::SIZE_SCOPE) > buff.size())
187     {
188         std::cerr << "Length of Scope size is greater than input buffer: "
189                   << (pos + slp::request::SIZE_SCOPE) << " / " << buff.size()
190                   << std::endl;
191         return (int)slp::Error::PARSE_ERROR;
192     }
193     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
194                 (uint8_t*)&scopeListLen);
195 
196     pos += slp::request::SIZE_SCOPE;
197 
198     scopeListLen = endian::from_network(scopeListLen);
199     if ((pos + scopeListLen) > buff.size())
200     {
201         std::cerr << "Length of Scope List is greater than input buffer: "
202                   << (pos + scopeListLen) << " / " << buff.size() << std::endl;
203         return (int)slp::Error::PARSE_ERROR;
204     }
205 
206     req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos,
207                                           scopeListLen);
208 
209     return slp::SUCCESS;
210 }
211 
parseSrvRqst(const buffer & buff,Message & req)212 int parseSrvRqst(const buffer& buff, Message& req)
213 {
214     /*  0                   1                   2                   3
215         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
216        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
217        |      length of <PRList>       |        <PRList> String        \
218        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219        |   length of <service-type>    |    <service-type> String      \
220        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
221        |    length of <scope-list>     |     <scope-list> String       \
222        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
223        |  length of predicate string   |  Service Request <predicate>  \
224        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
225        |  length of <SLP SPI> string   |       <SLP SPI> String        \
226        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
227 
228     /* Enforce v2 service request size limits. */
229     if (buff.size() < slp::request::MIN_SRV_LEN)
230     {
231         return (int)slp::Error::PARSE_ERROR;
232     }
233 
234     /* 1) Parse the PRList. */
235     uint16_t prListLen;
236     uint32_t pos = slp::header::MIN_LEN + req.header.langtagLen;
237     if ((pos + slp::request::SIZE_PRLIST) > buff.size())
238     {
239         std::cerr << "PRList length field is greater then input buffer: "
240                   << (pos + slp::request::SIZE_PRLIST) << " / " << buff.size()
241                   << std::endl;
242         return (int)slp::Error::PARSE_ERROR;
243     }
244     std::copy_n(buff.data() + pos, slp::request::SIZE_PRLIST,
245                 (uint8_t*)&prListLen);
246 
247     pos += slp::request::SIZE_PRLIST;
248 
249     prListLen = endian::from_network(prListLen);
250     if ((pos + prListLen) > buff.size())
251     {
252         std::cerr << "Length of PRList is greater then input buffer: "
253                   << (slp::request::OFFSET_PR + prListLen) << " / "
254                   << buff.size() << std::endl;
255         return (int)slp::Error::PARSE_ERROR;
256     }
257     req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos,
258                                    prListLen);
259 
260     pos += prListLen;
261 
262     /* 2) Parse the <service-type> string. */
263     uint16_t srvTypeLen;
264     if ((pos + slp::request::SIZE_SERVICE_TYPE) > buff.size())
265     {
266         std::cerr << "SrvType length field is greater then input buffer: "
267                   << (pos + slp::request::SIZE_SERVICE_TYPE) << " / "
268                   << buff.size() << std::endl;
269         return (int)slp::Error::PARSE_ERROR;
270     }
271     std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE,
272                 (uint8_t*)&srvTypeLen);
273 
274     srvTypeLen = endian::from_network(srvTypeLen);
275 
276     pos += slp::request::SIZE_SERVICE_TYPE;
277 
278     if ((pos + srvTypeLen) > buff.size())
279     {
280         std::cerr << "Length of SrvType is greater then input buffer: "
281                   << (pos + srvTypeLen) << " / " << buff.size() << std::endl;
282         return (int)slp::Error::PARSE_ERROR;
283     }
284     req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos,
285                                     srvTypeLen);
286 
287     pos += srvTypeLen;
288 
289     /* 3) Parse the <scope-list> string. */
290     uint16_t scopeListLen;
291     if ((pos + slp::request::SIZE_SCOPE) > buff.size())
292     {
293         std::cerr << "Scope List length field is greater then input buffer: "
294                   << (pos + slp::request::SIZE_SCOPE) << " / " << buff.size()
295                   << std::endl;
296         return (int)slp::Error::PARSE_ERROR;
297     }
298     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
299                 (uint8_t*)&scopeListLen);
300 
301     scopeListLen = endian::from_network(scopeListLen);
302 
303     pos += slp::request::SIZE_SCOPE;
304 
305     if ((pos + scopeListLen) > buff.size())
306     {
307         std::cerr << "Length of Scope List is greater then input buffer: "
308                   << (pos + scopeListLen) << " / " << buff.size() << std::endl;
309         return (int)slp::Error::PARSE_ERROR;
310     }
311     req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos,
312                                       scopeListLen);
313 
314     pos += scopeListLen;
315 
316     /* 4) Parse the <predicate> string. */
317     uint16_t predicateLen;
318     if ((pos + slp::request::SIZE_PREDICATE) > buff.size())
319     {
320         std::cerr << "Predicate length field is greater then input buffer: "
321                   << (pos + slp::request::SIZE_PREDICATE) << " / "
322                   << buff.size() << std::endl;
323         return (int)slp::Error::PARSE_ERROR;
324     }
325     std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE,
326                 (uint8_t*)&predicateLen);
327 
328     predicateLen = endian::from_network(predicateLen);
329     pos += slp::request::SIZE_PREDICATE;
330 
331     if ((pos + predicateLen) > buff.size())
332     {
333         std::cerr << "Length of Predicate is greater then input buffer: "
334                   << (pos + predicateLen) << " / " << buff.size() << std::endl;
335         return (int)slp::Error::PARSE_ERROR;
336     }
337     req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos,
338                                       predicateLen);
339 
340     pos += predicateLen;
341 
342     /* 5) Parse the <SLP SPI> string. */
343     uint16_t spistrLen;
344     if ((pos + slp::request::SIZE_SLPI) > buff.size())
345     {
346         std::cerr << "SLP SPI length field is greater then input buffer: "
347                   << (pos + slp::request::SIZE_SLPI) << " / " << buff.size()
348                   << std::endl;
349         return (int)slp::Error::PARSE_ERROR;
350     }
351     std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI,
352                 (uint8_t*)&spistrLen);
353 
354     spistrLen = endian::from_network(spistrLen);
355     pos += slp::request::SIZE_SLPI;
356 
357     if ((pos + spistrLen) > buff.size())
358     {
359         std::cerr << "Length of SLP SPI is greater then input buffer: "
360                   << (pos + spistrLen) << " / " << buff.size() << std::endl;
361         return (int)slp::Error::PARSE_ERROR;
362     }
363     req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos,
364                                    spistrLen);
365 
366     return slp::SUCCESS;
367 }
368 } // namespace internal
369 
parseBuffer(const buffer & buff)370 std::tuple<int, Message> parseBuffer(const buffer& buff)
371 {
372     Message req;
373     int rc = slp::SUCCESS;
374     /* parse the header first */
375     std::tie(rc, req) = internal::parseHeader(buff);
376     if (!rc)
377     {
378         /* switch on the function id to parse the body */
379         switch (req.header.functionID)
380         {
381             case (uint8_t)slp::FunctionType::SRVTYPERQST:
382                 rc = internal::parseSrvTypeRqst(buff, req);
383                 break;
384             case (uint8_t)slp::FunctionType::SRVRQST:
385                 rc = internal::parseSrvRqst(buff, req);
386                 break;
387             default:
388                 rc = (int)slp::Error::MSG_NOT_SUPPORTED;
389         }
390     }
391     return std::make_tuple(rc, std::move(req));
392 }
393 } // namespace parser
394 } // namespace slp
395