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