1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "CoAPPlatform.h"
9 #include "iotx_coap_internal.h"
10
CoAPDeserialize_Header(CoAPMessage * msg,unsigned char * buf)11 int CoAPDeserialize_Header(CoAPMessage *msg, unsigned char *buf)
12 {
13 msg->header.version = ((buf[0] >> 6) & 0x03);
14 msg->header.type = ((buf[0] >> 4) & 0x03);
15 msg->header.tokenlen = (buf[0] & 0x0F);
16 msg->header.code = buf[1];
17 msg->header.msgid = buf[2] << 8;
18 msg->header.msgid += buf[3];
19
20 return 4;
21 }
22
CoAPDeserialize_Token(CoAPMessage * msg,unsigned char * buf)23 int CoAPDeserialize_Token(CoAPMessage *msg, unsigned char *buf)
24 {
25 memcpy(msg->token, buf,
26 msg->header.tokenlen > COAP_MSG_MAX_TOKEN_LEN
27 ? COAP_MSG_MAX_TOKEN_LEN
28 : msg->header.tokenlen);
29 return msg->header.tokenlen;
30 }
31
32 #define COAP_OPT(o, e, step) do { \
33 if ((e) < step) { \
34 COAP_ERR("cannot advance opt past end"); \
35 return -1; \
36 } else { \
37 (e) -= step; \
38 (o) = ((o)) + step; \
39 } } while (0)
40
41 /*
42 * Used to prevent access to *option when pointing to after end of buffer
43 * after doing a COAP_OPT()
44 */
45 #define COAP_OPT_CHECK(o, e, step) \
46 do { \
47 COAP_OPT(o, e, step); \
48 if ((e) < 1) \
49 return -1; \
50 } while (0)
51
CoAPDeserialize_Option(CoAPMsgOption * option,unsigned char * buf,int left,unsigned short * predeltas)52 static int CoAPDeserialize_Option(CoAPMsgOption *option, unsigned char *buf,
53 int left, unsigned short *predeltas)
54 {
55 unsigned char *ptr = buf;
56 unsigned short optdelta = 0;
57 unsigned short optlen = 0;
58 unsigned short predelta = 0;
59
60 optdelta = (*ptr & 0xF0) >> 4;
61 optlen = (*ptr & 0x0F);
62
63 COAP_OPT_CHECK(ptr, left, 1);
64 predelta = *predeltas;
65 if (13 == optdelta) {
66 predelta += 13 + *ptr;
67 COAP_OPT_CHECK(ptr, left, 1);
68
69 } else if (14 == optdelta) {
70 predelta += 269;
71 predelta += (*ptr << 8);
72 predelta += *(ptr + 1);
73 COAP_OPT_CHECK(ptr, left, 2);
74 } else {
75 predelta += optdelta;
76 }
77 option->num = predelta;
78
79 if (13 == optlen) {
80 optlen = 13 + *ptr;
81 COAP_OPT_CHECK(ptr, left, 1);
82 } else if (14 == optlen) {
83 optlen = (*ptr << 8) + (*(ptr + 1));
84 if (optlen + 269 < 269) {
85 return -1;
86 }
87 optlen += 269;
88 COAP_OPT_CHECK(ptr, left, 2);
89 }
90 option->len = optlen;
91
92 option->val = ptr;
93 *predeltas = option->num;
94
95 return ptr - buf + option->len;
96 }
97
CoAPDeserialize_Options(CoAPMessage * msg,unsigned char * buf,int buflen)98 int CoAPDeserialize_Options(CoAPMessage *msg, unsigned char *buf, int buflen)
99 {
100 int index = 0;
101 int count = 0;
102 unsigned char *ptr = buf;
103 int len = 0;
104 int left = buflen;
105 unsigned short optdeltas = 0;
106
107 msg->optcount = 0;
108 while (left > 0 && (0xFF != *ptr) && index < COAP_MSG_MAX_OPTION_NUM) {
109 len =
110 CoAPDeserialize_Option(&msg->options[index], ptr, left, &optdeltas);
111 if (len < 0) {
112 return len;
113 }
114 msg->optcount += 1;
115 ptr += len;
116 left -= len;
117 index++;
118 }
119
120 return (int)(ptr - buf);
121 }
122
CoAPDeserialize_Payload(CoAPMessage * msg,unsigned char * buf,int buflen)123 int CoAPDeserialize_Payload(CoAPMessage *msg, unsigned char *buf, int buflen)
124 {
125 unsigned char *ptr = buf;
126
127 if (0xFF == *ptr) {
128 ptr++;
129 } else {
130 return 0;
131 }
132 msg->payloadlen = buflen - 1;
133 msg->payload = (unsigned char *)ptr;
134
135 return buflen;
136 }
137
CoAPDeserialize_Message(CoAPMessage * msg,unsigned char * buf,int buflen)138 int CoAPDeserialize_Message(CoAPMessage *msg, unsigned char *buf, int buflen)
139 {
140 int count = 0;
141 int remlen = buflen;
142 unsigned char *ptr = buf;
143
144 if (NULL == buf || NULL == msg) {
145 return COAP_ERROR_INVALID_PARAM;
146 }
147
148 if (buflen < 4) {
149 return COAP_ERROR_INVALID_LENGTH;
150 }
151
152 /* Deserialize CoAP header. */
153 count = CoAPDeserialize_Header(msg, ptr);
154 if (count > remlen) {
155 return COAP_ERROR_INVALID_LENGTH;
156 }
157 ptr += count;
158 remlen -= count;
159
160 /* Deserialize the token, if any. */
161 count = CoAPDeserialize_Token(msg, ptr);
162 if (count > remlen) {
163 return COAP_ERROR_INVALID_LENGTH;
164 }
165 ptr += count;
166 remlen -= count;
167
168 count = CoAPDeserialize_Options(msg, ptr, remlen);
169 if (count > remlen || count < 0) {
170 return COAP_ERROR_INVALID_LENGTH;
171 }
172 ptr += count;
173 remlen -= count;
174
175 CoAPDeserialize_Payload(msg, ptr, remlen);
176
177 return COAP_SUCCESS;
178 }
179