FreeRDP
tpdu.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdio.h>
23 #include <winpr/print.h>
24 
25 #include <freerdp/log.h>
26 
27 #include "tpdu.h"
28 
29 #define TAG FREERDP_TAG("core")
30 
66 static BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code);
67 
75 BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li, UINT16 tpktlength)
76 {
77  if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
78  return FALSE;
79 
80  Stream_Read_UINT8(s, *li); /* LI */
81  Stream_Read_UINT8(s, *code); /* Code */
82 
83  if (*li + 4 > tpktlength)
84  {
85  WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
86  return FALSE;
87  }
88 
89  if (*code == X224_TPDU_DATA)
90  {
91  /* EOT (1 byte) */
92  Stream_Seek(s, 1);
93  }
94  else
95  {
96  /* DST-REF (2 bytes) */
97  /* SRC-REF (2 bytes) */
98  /* Class 0 (1 byte) */
99  if (!Stream_SafeSeek(s, 5))
100  {
101  WLog_WARN(TAG, "tpdu invalid data, got %" PRIuz ", require at least 5 more",
102  Stream_GetRemainingLength(s));
103  return FALSE;
104  }
105  }
106 
107  return TRUE;
108 }
109 
117 BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code)
118 {
119  if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 3))
120  return FALSE;
121 
122  WINPR_ASSERT(length <= UINT8_MAX);
123  Stream_Write_UINT8(s, (UINT8)length); /* LI */
124  Stream_Write_UINT8(s, code); /* code */
125 
126  if (code == X224_TPDU_DATA)
127  {
128  Stream_Write_UINT8(s, 0x80); /* EOT */
129  }
130  else
131  {
132  if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 5))
133  return FALSE;
134  Stream_Write_UINT16(s, 0); /* DST-REF */
135  Stream_Write_UINT16(s, 0); /* SRC-REF */
136  Stream_Write_UINT8(s, 0); /* Class 0 */
137  }
138  return TRUE;
139 }
140 
147 BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
148 {
149  BYTE code = 0;
150 
151  if (!tpdu_read_header(s, &code, li, tpktlength))
152  return FALSE;
153 
154  if (code != X224_TPDU_CONNECTION_REQUEST)
155  {
156  WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
157  return FALSE;
158  }
159 
160  return TRUE;
161 }
162 
169 BOOL tpdu_write_connection_request(wStream* s, UINT16 length)
170 {
171  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
172 }
173 
180 BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
181 {
182  BYTE code = 0;
183  size_t position = 0;
184  size_t bytes_read = 0;
185 
186  /* save the position to determine the number of bytes read */
187  position = Stream_GetPosition(s);
188 
189  if (!tpdu_read_header(s, &code, li, tpktlength))
190  return FALSE;
191 
192  if (code != X224_TPDU_CONNECTION_CONFIRM)
193  {
194  WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
195  return FALSE;
196  }
197  /*
198  * To ensure that there are enough bytes remaining for processing
199  * check against the length indicator (li). Already read bytes need
200  * to be taken into account.
201  * The -1 is because li was read but isn't included in the TPDU size.
202  * For reference see ITU-T Rec. X.224 - 13.2.1
203  */
204  bytes_read = (Stream_GetPosition(s) - position) - 1;
205 
206  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(*li - bytes_read)))
207  return FALSE;
208  return TRUE;
209 }
210 
217 BOOL tpdu_write_connection_confirm(wStream* s, UINT16 length)
218 {
219  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
220 }
221 
228 BOOL tpdu_write_disconnect_request(wStream* s, UINT16 length)
229 {
230  return tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
231 }
232 
238 BOOL tpdu_write_data(wStream* s)
239 {
240  return tpdu_write_header(s, 2, X224_TPDU_DATA);
241 }
242 
248 BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
249 {
250  BYTE code = 0;
251  BYTE li = 0;
252 
253  if (!tpdu_read_header(s, &code, &li, tpktlength))
254  return FALSE;
255 
256  if (code != X224_TPDU_DATA)
257  {
258  WLog_ERR(TAG, "tpdu got code 0x%02" PRIx8 " expected X224_TPDU_DATA [0x%02x]", code,
259  X224_TPDU_DATA);
260  return FALSE;
261  }
262 
263  *LI = li;
264 
265  return TRUE;
266 }
267 
268 const char* tpdu_type_to_string(int type)
269 {
270  switch (type)
271  {
272  case X224_TPDU_CONNECTION_REQUEST:
273  return "X224_TPDU_CONNECTION_REQUEST";
274  case X224_TPDU_CONNECTION_CONFIRM:
275  return "X224_TPDU_CONNECTION_CONFIRM";
276  case X224_TPDU_DISCONNECT_REQUEST:
277  return "X224_TPDU_DISCONNECT_REQUEST";
278  case X224_TPDU_DATA:
279  return "X224_TPDU_DATA";
280  case X224_TPDU_ERROR:
281  return "X224_TPDU_ERROR";
282  default:
283  return "X224_TPDU_UNKNOWN";
284  }
285 }