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