snmp_asn1.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /**
  2. * @file
  3. * Abstract Syntax Notation One (ISO 8824, 8825) encoding
  4. *
  5. * @todo not optimised (yet), favor correctness over speed, favor speed over size
  6. */
  7. /*
  8. * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without modification,
  12. * are permitted provided that the following conditions are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright notice,
  15. * this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright notice,
  17. * this list of conditions and the following disclaimer in the documentation
  18. * and/or other materials provided with the distribution.
  19. * 3. The name of the author may not be used to endorse or promote products
  20. * derived from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  23. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  24. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  25. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  27. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  30. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  31. * OF SUCH DAMAGE.
  32. *
  33. * Author: Christiaan Simons <christiaan.simons@axon.tv>
  34. * Martin Hentschel <info@cl-soft.de>
  35. */
  36. #include "lwip/apps/snmp_opts.h"
  37. #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
  38. #include "snmp_asn1.h"
  39. #define PBUF_OP_EXEC(code) \
  40. if ((code) != ERR_OK) { \
  41. return ERR_BUF; \
  42. }
  43. /**
  44. * Encodes a TLV into a pbuf stream.
  45. *
  46. * @param pbuf_stream points to a pbuf stream
  47. * @param tlv TLV to encode
  48. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  49. */
  50. err_t
  51. snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
  52. {
  53. u8_t data;
  54. u8_t length_bytes_required;
  55. /* write type */
  56. if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
  57. /* extended format is not used by SNMP so we do not accept those values */
  58. return ERR_ARG;
  59. }
  60. if (tlv->type_len != 0) {
  61. /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
  62. return ERR_ARG;
  63. }
  64. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
  65. tlv->type_len = 1;
  66. /* write length */
  67. if (tlv->value_len <= 127) {
  68. length_bytes_required = 1;
  69. } else if (tlv->value_len <= 255) {
  70. length_bytes_required = 2;
  71. } else {
  72. length_bytes_required = 3;
  73. }
  74. /* check for forced min length */
  75. if (tlv->length_len > 0) {
  76. if (tlv->length_len < length_bytes_required) {
  77. /* unable to code requested length in requested number of bytes */
  78. return ERR_ARG;
  79. }
  80. length_bytes_required = tlv->length_len;
  81. } else {
  82. tlv->length_len = length_bytes_required;
  83. }
  84. if (length_bytes_required > 1) {
  85. /* multi byte representation required */
  86. length_bytes_required--;
  87. data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
  88. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
  89. while (length_bytes_required > 1) {
  90. if (length_bytes_required == 2) {
  91. /* append high byte */
  92. data = (u8_t)(tlv->value_len >> 8);
  93. } else {
  94. /* append leading 0x00 */
  95. data = 0x00;
  96. }
  97. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
  98. length_bytes_required--;
  99. }
  100. }
  101. /* append low byte */
  102. data = (u8_t)(tlv->value_len & 0xFF);
  103. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
  104. return ERR_OK;
  105. }
  106. /**
  107. * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
  108. *
  109. * @param pbuf_stream points to a pbuf stream
  110. * @param raw_len raw data length
  111. * @param raw points raw data
  112. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  113. */
  114. err_t
  115. snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
  116. {
  117. PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
  118. return ERR_OK;
  119. }
  120. /**
  121. * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
  122. *
  123. * @param pbuf_stream points to a pbuf stream
  124. * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
  125. * @param value is the host order u32_t value to be encoded
  126. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  127. *
  128. * @see snmp_asn1_enc_u32t_cnt()
  129. */
  130. err_t
  131. snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
  132. {
  133. if (octets_needed > 5) {
  134. return ERR_ARG;
  135. }
  136. if (octets_needed == 5) {
  137. /* not enough bits in 'value' add leading 0x00 */
  138. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
  139. octets_needed--;
  140. }
  141. while (octets_needed > 1) {
  142. octets_needed--;
  143. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
  144. }
  145. /* (only) one least significant octet */
  146. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
  147. return ERR_OK;
  148. }
  149. /**
  150. * Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
  151. *
  152. * @param pbuf_stream points to a pbuf stream
  153. * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
  154. * @param value is the host order u32_t value to be encoded
  155. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  156. *
  157. * @see snmp_asn1_enc_u64t_cnt()
  158. */
  159. err_t
  160. snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
  161. {
  162. if (octets_needed > 9) {
  163. return ERR_ARG;
  164. }
  165. if (octets_needed == 9) {
  166. /* not enough bits in 'value' add leading 0x00 */
  167. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
  168. octets_needed--;
  169. }
  170. while (octets_needed > 4) {
  171. octets_needed--;
  172. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
  173. }
  174. /* skip to low u32 */
  175. value++;
  176. while (octets_needed > 1) {
  177. octets_needed--;
  178. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
  179. }
  180. /* always write at least one octet (also in case of value == 0) */
  181. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
  182. return ERR_OK;
  183. }
  184. /**
  185. * Encodes s32_t integer into a pbuf chained ASN1 msg.
  186. *
  187. * @param pbuf_stream points to a pbuf stream
  188. * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
  189. * @param value is the host order s32_t value to be encoded
  190. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  191. *
  192. * @see snmp_asn1_enc_s32t_cnt()
  193. */
  194. err_t
  195. snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
  196. {
  197. while (octets_needed > 1) {
  198. octets_needed--;
  199. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
  200. }
  201. /* (only) one least significant octet */
  202. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
  203. return ERR_OK;
  204. }
  205. /**
  206. * Encodes object identifier into a pbuf chained ASN1 msg.
  207. *
  208. * @param pbuf_stream points to a pbuf stream
  209. * @param oid points to object identifier array
  210. * @param oid_len object identifier array length
  211. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
  212. */
  213. err_t
  214. snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
  215. {
  216. if (oid_len > 1) {
  217. /* write compressed first two sub id's */
  218. u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
  219. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
  220. oid_len -= 2;
  221. oid += 2;
  222. } else {
  223. /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
  224. /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
  225. return ERR_ARG;
  226. }
  227. while (oid_len > 0) {
  228. u32_t sub_id;
  229. u8_t shift, tail;
  230. oid_len--;
  231. sub_id = *oid;
  232. tail = 0;
  233. shift = 28;
  234. while (shift > 0) {
  235. u8_t code;
  236. code = (u8_t)(sub_id >> shift);
  237. if ((code != 0) || (tail != 0)) {
  238. tail = 1;
  239. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
  240. }
  241. shift -= 7;
  242. }
  243. PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
  244. /* proceed to next sub-identifier */
  245. oid++;
  246. }
  247. return ERR_OK;
  248. }
  249. /**
  250. * Returns octet count for length.
  251. *
  252. * @param length parameter length
  253. * @param octets_needed points to the return value
  254. */
  255. void
  256. snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
  257. {
  258. if (length < 0x80U) {
  259. *octets_needed = 1;
  260. } else if (length < 0x100U) {
  261. *octets_needed = 2;
  262. } else {
  263. *octets_needed = 3;
  264. }
  265. }
  266. /**
  267. * Returns octet count for an u32_t.
  268. *
  269. * @param value value to be encoded
  270. * @param octets_needed points to the return value
  271. *
  272. * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
  273. * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
  274. * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
  275. */
  276. void
  277. snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
  278. {
  279. if (value < 0x80UL) {
  280. *octets_needed = 1;
  281. } else if (value < 0x8000UL) {
  282. *octets_needed = 2;
  283. } else if (value < 0x800000UL) {
  284. *octets_needed = 3;
  285. } else if (value < 0x80000000UL) {
  286. *octets_needed = 4;
  287. } else {
  288. *octets_needed = 5;
  289. }
  290. }
  291. /**
  292. * Returns octet count for an u64_t.
  293. *
  294. * @param value value to be encoded
  295. * @param octets_needed points to the return value
  296. *
  297. * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
  298. * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
  299. * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
  300. */
  301. void
  302. snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
  303. {
  304. /* check if high u32 is 0 */
  305. if (*value == 0x00) {
  306. /* only low u32 is important */
  307. value++;
  308. snmp_asn1_enc_u32t_cnt(*value, octets_needed);
  309. } else {
  310. /* low u32 does not matter for length determination */
  311. snmp_asn1_enc_u32t_cnt(*value, octets_needed);
  312. *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
  313. }
  314. }
  315. /**
  316. * Returns octet count for an s32_t.
  317. *
  318. * @param value value to be encoded
  319. * @param octets_needed points to the return value
  320. *
  321. * @note ASN coded integers are _always_ signed.
  322. */
  323. void
  324. snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
  325. {
  326. if (value < 0) {
  327. value = ~value;
  328. }
  329. if (value < 0x80L) {
  330. *octets_needed = 1;
  331. } else if (value < 0x8000L) {
  332. *octets_needed = 2;
  333. } else if (value < 0x800000L) {
  334. *octets_needed = 3;
  335. } else {
  336. *octets_needed = 4;
  337. }
  338. }
  339. /**
  340. * Returns octet count for an object identifier.
  341. *
  342. * @param oid points to object identifier array
  343. * @param oid_len object identifier array length
  344. * @param octets_needed points to the return value
  345. */
  346. void
  347. snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
  348. {
  349. u32_t sub_id;
  350. *octets_needed = 0;
  351. if (oid_len > 1) {
  352. /* compressed prefix in one octet */
  353. (*octets_needed)++;
  354. oid_len -= 2;
  355. oid += 2;
  356. }
  357. while (oid_len > 0) {
  358. oid_len--;
  359. sub_id = *oid;
  360. sub_id >>= 7;
  361. (*octets_needed)++;
  362. while (sub_id > 0) {
  363. sub_id >>= 7;
  364. (*octets_needed)++;
  365. }
  366. oid++;
  367. }
  368. }
  369. /**
  370. * Decodes a TLV from a pbuf stream.
  371. *
  372. * @param pbuf_stream points to a pbuf stream
  373. * @param tlv returns decoded TLV
  374. * @return ERR_OK if successful, ERR_VAL if we can't decode
  375. */
  376. err_t
  377. snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
  378. {
  379. u8_t data;
  380. /* decode type first */
  381. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  382. tlv->type = data;
  383. if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
  384. /* extended format is not used by SNMP so we do not accept those values */
  385. return ERR_VAL;
  386. }
  387. tlv->type_len = 1;
  388. /* now, decode length */
  389. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  390. if (data < 0x80) { /* short form */
  391. tlv->length_len = 1;
  392. tlv->value_len = data;
  393. } else if (data > 0x80) { /* long form */
  394. u8_t length_bytes = data - 0x80;
  395. tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
  396. tlv->value_len = 0;
  397. while (length_bytes > 0) {
  398. /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
  399. if (tlv->value_len > 0xFF) {
  400. return ERR_VAL;
  401. }
  402. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  403. tlv->value_len <<= 8;
  404. tlv->value_len |= data;
  405. /* take care for special value used for indefinite length */
  406. if (tlv->value_len == 0xFFFF) {
  407. return ERR_VAL;
  408. }
  409. length_bytes--;
  410. }
  411. } else { /* data == 0x80 indefinite length form */
  412. /* (not allowed for SNMP; RFC 1157, 3.2.2) */
  413. return ERR_VAL;
  414. }
  415. return ERR_OK;
  416. }
  417. /**
  418. * Decodes positive integer (counter, gauge, timeticks) into u32_t.
  419. *
  420. * @param pbuf_stream points to a pbuf stream
  421. * @param len length of the coded integer field
  422. * @param value return host order integer
  423. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
  424. *
  425. * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
  426. * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
  427. * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
  428. */
  429. err_t
  430. snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
  431. {
  432. u8_t data;
  433. if ((len > 0) && (len <= 5)) {
  434. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  435. /* expecting sign bit to be zero, only unsigned please! */
  436. if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
  437. *value = data;
  438. len--;
  439. while (len > 0) {
  440. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  441. len--;
  442. *value <<= 8;
  443. *value |= data;
  444. }
  445. return ERR_OK;
  446. }
  447. }
  448. return ERR_VAL;
  449. }
  450. /**
  451. * Decodes large positive integer (counter64) into 2x u32_t.
  452. *
  453. * @param pbuf_stream points to a pbuf stream
  454. * @param len length of the coded integer field
  455. * @param value return host order integer
  456. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
  457. *
  458. * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
  459. * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
  460. * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
  461. */
  462. err_t
  463. snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
  464. {
  465. u8_t data;
  466. if (len <= 4) {
  467. /* high u32 is 0 */
  468. *value = 0;
  469. /* directly skip to low u32 */
  470. value++;
  471. }
  472. if ((len > 0) && (len <= 9)) {
  473. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  474. /* expecting sign bit to be zero, only unsigned please! */
  475. if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
  476. *value = data;
  477. len--;
  478. while (len > 0) {
  479. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  480. if (len == 4) {
  481. /* skip to low u32 */
  482. value++;
  483. *value = 0;
  484. } else {
  485. *value <<= 8;
  486. }
  487. *value |= data;
  488. len--;
  489. }
  490. return ERR_OK;
  491. }
  492. }
  493. return ERR_VAL;
  494. }
  495. /**
  496. * Decodes integer into s32_t.
  497. *
  498. * @param pbuf_stream points to a pbuf stream
  499. * @param len length of the coded integer field
  500. * @param value return host order integer
  501. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
  502. *
  503. * @note ASN coded integers are _always_ signed!
  504. */
  505. err_t
  506. snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
  507. {
  508. #if BYTE_ORDER == LITTLE_ENDIAN
  509. u8_t *lsb_ptr = (u8_t*)value;
  510. #endif
  511. #if BYTE_ORDER == BIG_ENDIAN
  512. u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
  513. #endif
  514. u8_t sign;
  515. u8_t data;
  516. if ((len > 0) && (len < 5)) {
  517. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  518. len--;
  519. if (data & 0x80) {
  520. /* negative, start from -1 */
  521. *value = -1;
  522. sign = 1;
  523. *lsb_ptr &= data;
  524. } else {
  525. /* positive, start from 0 */
  526. *value = 0;
  527. sign = 0;
  528. *lsb_ptr |= data;
  529. }
  530. /* OR/AND octets with value */
  531. while (len > 0) {
  532. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  533. len--;
  534. #if BYTE_ORDER == LITTLE_ENDIAN
  535. *value <<= 8;
  536. #endif
  537. #if BYTE_ORDER == BIG_ENDIAN
  538. *value >>= 8;
  539. #endif
  540. if (sign) {
  541. *lsb_ptr |= 255;
  542. *lsb_ptr &= data;
  543. } else {
  544. *lsb_ptr |= data;
  545. }
  546. }
  547. return ERR_OK;
  548. }
  549. return ERR_VAL;
  550. }
  551. /**
  552. * Decodes object identifier from incoming message into array of u32_t.
  553. *
  554. * @param pbuf_stream points to a pbuf stream
  555. * @param len length of the coded object identifier
  556. * @param oid return decoded object identifier
  557. * @param oid_len return decoded object identifier length
  558. * @param oid_max_len size of oid buffer
  559. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
  560. */
  561. err_t
  562. snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
  563. {
  564. u32_t *oid_ptr;
  565. u8_t data;
  566. *oid_len = 0;
  567. oid_ptr = oid;
  568. if (len > 0) {
  569. if (oid_max_len < 2) {
  570. return ERR_MEM;
  571. }
  572. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  573. len--;
  574. /* first compressed octet */
  575. if (data == 0x2B) {
  576. /* (most) common case 1.3 (iso.org) */
  577. *oid_ptr = 1;
  578. oid_ptr++;
  579. *oid_ptr = 3;
  580. oid_ptr++;
  581. } else if (data < 40) {
  582. *oid_ptr = 0;
  583. oid_ptr++;
  584. *oid_ptr = data;
  585. oid_ptr++;
  586. } else if (data < 80) {
  587. *oid_ptr = 1;
  588. oid_ptr++;
  589. *oid_ptr = data - 40;
  590. oid_ptr++;
  591. } else {
  592. *oid_ptr = 2;
  593. oid_ptr++;
  594. *oid_ptr = data - 80;
  595. oid_ptr++;
  596. }
  597. *oid_len = 2;
  598. } else {
  599. /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
  600. return ERR_OK;
  601. }
  602. while ((len > 0) && (*oid_len < oid_max_len)) {
  603. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  604. len--;
  605. if ((data & 0x80) == 0x00) {
  606. /* sub-identifier uses single octet */
  607. *oid_ptr = data;
  608. } else {
  609. /* sub-identifier uses multiple octets */
  610. u32_t sub_id = (data & ~0x80);
  611. while ((len > 0) && ((data & 0x80) != 0)) {
  612. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
  613. len--;
  614. sub_id = (sub_id << 7) + (data & ~0x80);
  615. }
  616. if ((data & 0x80) != 0) {
  617. /* "more bytes following" bit still set at end of len */
  618. return ERR_VAL;
  619. }
  620. *oid_ptr = sub_id;
  621. }
  622. oid_ptr++;
  623. (*oid_len)++;
  624. }
  625. if (len > 0) {
  626. /* OID to long to fit in our buffer */
  627. return ERR_MEM;
  628. }
  629. return ERR_OK;
  630. }
  631. /**
  632. * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
  633. * from incoming message into array.
  634. *
  635. * @param pbuf_stream points to a pbuf stream
  636. * @param len length of the coded raw data (zero is valid, e.g. empty string!)
  637. * @param buf return raw bytes
  638. * @param buf_len returns length of the raw return value
  639. * @param buf_max_len buffer size
  640. * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
  641. */
  642. err_t
  643. snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
  644. {
  645. if (len > buf_max_len) {
  646. /* not enough dst space */
  647. return ERR_MEM;
  648. }
  649. *buf_len = len;
  650. while (len > 0) {
  651. PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
  652. buf++;
  653. len--;
  654. }
  655. return ERR_OK;
  656. }
  657. #endif /* LWIP_SNMP */