summaryrefslogtreecommitdiffstats
path: root/libfreerdp/core/tpdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/core/tpdu.c')
-rw-r--r--libfreerdp/core/tpdu.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/libfreerdp/core/tpdu.c b/libfreerdp/core/tpdu.c
new file mode 100644
index 0000000..9718cb1
--- /dev/null
+++ b/libfreerdp/core/tpdu.c
@@ -0,0 +1,284 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * X.224 Transport Protocol Data Units (TPDUs)
+ *
+ * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <freerdp/config.h>
+
+#include <stdio.h>
+#include <winpr/print.h>
+
+#include <freerdp/log.h>
+
+#include "tpdu.h"
+
+#define TAG FREERDP_TAG("core")
+
+/**
+ * TPDUs are defined in:
+ *
+ * http://www.itu.int/rec/T-REC-X.224-199511-I/
+ * X.224: Information technology - Open Systems Interconnection - Protocol for providing the
+ * connection-mode transport service
+ *
+ * RDP uses only TPDUs of class 0, the "simple class" defined in section 8 of X.224
+ *
+ * TPDU Header
+ * ____________________ byte
+ * | |
+ * | LI | 1
+ * |____________________|
+ * | |
+ * | Code | 2
+ * |____________________|
+ * | |
+ * | | 3
+ * |_______DST-REF______|
+ * | |
+ * | | 4
+ * |____________________|
+ * | |
+ * | | 5
+ * |_______SRC-REF______|
+ * | |
+ * | | 6
+ * |____________________|
+ * | |
+ * | Class | 7
+ * |____________________|
+ * | ... |
+ */
+
+static BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code);
+
+/**
+ * Read TPDU header.
+ * @param s stream
+ * @param code variable pointer to receive TPDU code
+ * @return TPDU length indicator (LI)
+ */
+
+BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li, UINT16 tpktlength)
+{
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
+ return FALSE;
+
+ Stream_Read_UINT8(s, *li); /* LI */
+ Stream_Read_UINT8(s, *code); /* Code */
+
+ if (*li + 4 > tpktlength)
+ {
+ WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
+ return FALSE;
+ }
+
+ if (*code == X224_TPDU_DATA)
+ {
+ /* EOT (1 byte) */
+ Stream_Seek(s, 1);
+ }
+ else
+ {
+ /* DST-REF (2 bytes) */
+ /* SRC-REF (2 bytes) */
+ /* Class 0 (1 byte) */
+ if (!Stream_SafeSeek(s, 5))
+ {
+ WLog_WARN(TAG, "tpdu invalid data, got %" PRIuz ", require at least 5 more",
+ Stream_GetRemainingLength(s));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * Write TDPU header.
+ * @param s stream
+ * @param length length
+ * @param code TPDU code
+ */
+
+BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code)
+{
+ if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 3))
+ return FALSE;
+
+ Stream_Write_UINT8(s, length); /* LI */
+ Stream_Write_UINT8(s, code); /* code */
+
+ if (code == X224_TPDU_DATA)
+ {
+ Stream_Write_UINT8(s, 0x80); /* EOT */
+ }
+ else
+ {
+ if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 5))
+ return FALSE;
+ Stream_Write_UINT16(s, 0); /* DST-REF */
+ Stream_Write_UINT16(s, 0); /* SRC-REF */
+ Stream_Write_UINT8(s, 0); /* Class 0 */
+ }
+ return TRUE;
+}
+
+/**
+ * Read Connection Request TPDU
+ * @param s stream
+ * @return length indicator (LI)
+ */
+
+BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
+{
+ BYTE code = 0;
+
+ if (!tpdu_read_header(s, &code, li, tpktlength))
+ return FALSE;
+
+ if (code != X224_TPDU_CONNECTION_REQUEST)
+ {
+ WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * Write Connection Request TPDU.
+ * @param s stream
+ * @param length TPDU length
+ */
+
+BOOL tpdu_write_connection_request(wStream* s, UINT16 length)
+{
+ return tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
+}
+
+/**
+ * Read Connection Confirm TPDU.
+ * @param s stream
+ * @return length indicator (LI)
+ */
+
+BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
+{
+ BYTE code = 0;
+ size_t position = 0;
+ size_t bytes_read = 0;
+
+ /* save the position to determine the number of bytes read */
+ position = Stream_GetPosition(s);
+
+ if (!tpdu_read_header(s, &code, li, tpktlength))
+ return FALSE;
+
+ if (code != X224_TPDU_CONNECTION_CONFIRM)
+ {
+ WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
+ return FALSE;
+ }
+ /*
+ * To ensure that there are enough bytes remaining for processing
+ * check against the length indicator (li). Already read bytes need
+ * to be taken into account.
+ * The -1 is because li was read but isn't included in the TPDU size.
+ * For reference see ITU-T Rec. X.224 - 13.2.1
+ */
+ bytes_read = (Stream_GetPosition(s) - position) - 1;
+
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(*li - bytes_read)))
+ return FALSE;
+ return TRUE;
+}
+
+/**
+ * Write Connection Confirm TPDU.
+ * @param s stream
+ * @param length TPDU length
+ */
+
+BOOL tpdu_write_connection_confirm(wStream* s, UINT16 length)
+{
+ return tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
+}
+
+/**
+ * Write Disconnect Request TPDU.
+ * @param s stream
+ * @param length TPDU length
+ */
+
+BOOL tpdu_write_disconnect_request(wStream* s, UINT16 length)
+{
+ return tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
+}
+
+/**
+ * Write Data TPDU.
+ * @param s stream
+ */
+
+BOOL tpdu_write_data(wStream* s)
+{
+ return tpdu_write_header(s, 2, X224_TPDU_DATA);
+}
+
+/**
+ * Read Data TPDU.
+ * @param s stream
+ */
+
+BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
+{
+ BYTE code = 0;
+ BYTE li = 0;
+
+ if (!tpdu_read_header(s, &code, &li, tpktlength))
+ return FALSE;
+
+ if (code != X224_TPDU_DATA)
+ {
+ WLog_ERR(TAG, "tpdu got code 0x%02" PRIx8 " expected X224_TPDU_DATA [0x%02x]", code,
+ X224_TPDU_DATA);
+ return FALSE;
+ }
+
+ *LI = li;
+
+ return TRUE;
+}
+
+const char* tpdu_type_to_string(int type)
+{
+ switch (type)
+ {
+ case X224_TPDU_CONNECTION_REQUEST:
+ return "X224_TPDU_CONNECTION_REQUEST";
+ case X224_TPDU_CONNECTION_CONFIRM:
+ return "X224_TPDU_CONNECTION_CONFIRM";
+ case X224_TPDU_DISCONNECT_REQUEST:
+ return "X224_TPDU_DISCONNECT_REQUEST";
+ case X224_TPDU_DATA:
+ return "X224_TPDU_DATA";
+ case X224_TPDU_ERROR:
+ return "X224_TPDU_ERROR";
+ default:
+ return "X224_TPDU_UNKNOWN";
+ }
+}