xref: /openbmc/slpd-lite/slp_parser.cpp (revision c668313e)
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         // 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.langtag.insert(
81                 0, (const char*)buff.data() + slp::header::OFFSET_LANG,
82                 langtagLen);
83 
84             /* check for the validity of the function */
85             if (req.header.functionID <
86                     static_cast<uint8_t>(slp::FunctionType::SRVRQST) ||
87                 req.header.functionID >
88                     static_cast<uint8_t>(slp::FunctionType::SAADV))
89             {
90                 std::cerr << "Invalid function ID: " << req.header.functionID
91                           << std::endl;
92                 rc = static_cast<int>(slp::Error::PARSE_ERROR);
93             }
94         }
95     }
96 
97     return std::make_tuple(rc, std::move(req));
98 }
99 
100 int parseSrvTypeRqst(const buffer& buff, Message& req)
101 {
102     /*  0                   1                   2                   3
103         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
104        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105        |        length of PRList       |        <PRList> String        \
106        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107        |   length of Naming Authority  |   <Naming Authority String>   \
108        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109        |     length of <scope-list>    |      <scope-list> String      \
110        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
111 
112     /* Enforce SLPv2 service type request size limits. */
113     if (buff.size() < slp::request::MIN_SRVTYPE_LEN)
114     {
115         return (int)slp::Error::PARSE_ERROR;
116     }
117 
118     /* Parse the PRList. */
119     uint16_t prListLen;
120     std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
121                 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen);
122 
123     prListLen = endian::from_network(prListLen);
124 
125     req.body.srvtyperqst.prList.insert(
126         0, (const char*)buff.data() + slp::request::OFFSET_PR, prListLen);
127 
128     uint8_t pos = slp::request::OFFSET_PR + prListLen;
129 
130     /* Parse the Naming Authority. */
131     uint16_t namingAuthLen;
132     std::copy_n(buff.data() + pos, slp::request::SIZE_NAMING,
133                 (uint8_t*)&namingAuthLen);
134 
135     pos += slp::request::SIZE_NAMING;
136 
137     namingAuthLen = endian::from_network(namingAuthLen);
138 
139     if (namingAuthLen == 0 || namingAuthLen == 0xffff)
140     {
141         req.body.srvtyperqst.namingAuth = "";
142     }
143     else
144     {
145         req.body.srvtyperqst.namingAuth.insert(
146             0, (const char*)buff.data() + pos, namingAuthLen);
147     }
148 
149     pos += namingAuthLen;
150 
151     /* Parse the <scope-list>. */
152     uint16_t scopeListLen;
153     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
154                 (uint8_t*)&scopeListLen);
155 
156     pos += slp::request::SIZE_SCOPE;
157 
158     scopeListLen = endian::from_network(scopeListLen);
159 
160     req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos,
161                                           scopeListLen);
162 
163     return slp::SUCCESS;
164 }
165 
166 int parseSrvRqst(const buffer& buff, Message& req)
167 {
168     /*  0                   1                   2                   3
169         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
170        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171        |      length of <PRList>       |        <PRList> String        \
172        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173        |   length of <service-type>    |    <service-type> String      \
174        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175        |    length of <scope-list>     |     <scope-list> String       \
176        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177        |  length of predicate string   |  Service Request <predicate>  \
178        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179        |  length of <SLP SPI> string   |       <SLP SPI> String        \
180        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
181 
182     /* Enforce v2 service request size limits. */
183     if (buff.size() < slp::request::MIN_SRV_LEN)
184     {
185         return (int)slp::Error::PARSE_ERROR;
186     }
187 
188     /* 1) Parse the PRList. */
189     uint16_t prListLen;
190     std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
191                 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen);
192 
193     auto pos = slp::request::OFFSET_PR_LEN + slp::request::SIZE_PRLIST;
194 
195     prListLen = endian::from_network(prListLen);
196 
197     req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos,
198                                    prListLen);
199 
200     pos += prListLen;
201 
202     /* 2) Parse the <service-type> string. */
203     uint16_t srvTypeLen;
204     std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE,
205                 (uint8_t*)&srvTypeLen);
206 
207     srvTypeLen = endian::from_network(srvTypeLen);
208 
209     pos += slp::request::SIZE_SERVICE_TYPE;
210 
211     req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos,
212                                     srvTypeLen);
213 
214     pos += srvTypeLen;
215 
216     /* 3) Parse the <scope-list> string. */
217     uint16_t scopeListLen;
218     std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
219                 (uint8_t*)&scopeListLen);
220 
221     scopeListLen = endian::from_network(scopeListLen);
222 
223     pos += slp::request::SIZE_SCOPE;
224 
225     req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos,
226                                       scopeListLen);
227 
228     pos += scopeListLen;
229 
230     /* 4) Parse the <predicate> string. */
231     uint16_t predicateLen;
232     std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE,
233                 (uint8_t*)&predicateLen);
234 
235     predicateLen = endian::from_network(predicateLen);
236     pos += slp::request::SIZE_PREDICATE;
237 
238     req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos,
239                                       predicateLen);
240 
241     pos += predicateLen;
242 
243     /* 5) Parse the <SLP SPI> string. */
244     uint16_t spistrLen;
245     std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI,
246                 (uint8_t*)&spistrLen);
247 
248     spistrLen = endian::from_network(spistrLen);
249     pos += slp::request::SIZE_SLPI;
250 
251     req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos,
252                                    spistrLen);
253 
254     return slp::SUCCESS;
255 }
256 } // namespace internal
257 
258 std::tuple<int, Message> parseBuffer(const buffer& buff)
259 {
260     Message req;
261     int rc = slp::SUCCESS;
262     /* parse the header first */
263     std::tie(rc, req) = internal::parseHeader(buff);
264     if (!rc)
265     {
266         /* switch on the function id to parse the body */
267         switch (req.header.functionID)
268         {
269             case (uint8_t)slp::FunctionType::SRVTYPERQST:
270                 rc = internal::parseSrvTypeRqst(buff, req);
271                 break;
272             case (uint8_t)slp::FunctionType::SRVRQST:
273                 rc = internal::parseSrvRqst(buff, req);
274                 break;
275             default:
276                 rc = (int)slp::Error::MSG_NOT_SUPPORTED;
277         }
278     }
279     return std::make_tuple(rc, std::move(req));
280 }
281 } // namespace parser
282 } // namespace slp
283