1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - ISO layer
4    Copyright (C) Matthew Chapman 1999-2005
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "rdesktop.h"
22 
23 /* Send a self-contained ISO PDU */
24 static BOOL
25 iso_send_msg(RDPCLIENT * This, uint8 code)
26 {
27 	STREAM s;
28 
29 	s = tcp_init(This, 11);
30 
31 	if(s == NULL)
32 		return False;
33 
34 	out_uint8(s, 3);	/* version */
35 	out_uint8(s, 0);	/* reserved */
36 	out_uint16_be(s, 11);	/* length */
37 
38 	out_uint8(s, 6);	/* hdrlen */
39 	out_uint8(s, code);
40 	out_uint16(s, 0);	/* dst_ref */
41 	out_uint16(s, 0);	/* src_ref */
42 	out_uint8(s, 0);	/* class */
43 
44 	s_mark_end(s);
45 	return tcp_send(This, s);
46 }
47 
48 static BOOL
49 iso_send_connection_request(RDPCLIENT * This, char *cookie)
50 {
51 	STREAM s;
52 	int cookielen = (int)strlen(cookie);
53 	int length = 11 + cookielen;
54 
55 	s = tcp_init(This, length);
56 
57 	if(s == NULL)
58 		return False;
59 
60 	out_uint8(s, 3);	/* version */
61 	out_uint8(s, 0);	/* reserved */
62 	out_uint16_be(s, length);	/* length */
63 
64 	out_uint8(s, length - 5);	/* hdrlen */
65 	out_uint8(s, ISO_PDU_CR);
66 	out_uint16(s, 0);	/* dst_ref */
67 	out_uint16(s, 0);	/* src_ref */
68 	out_uint8(s, 0);	/* class */
69 
70 	out_uint8p(s, cookie, cookielen);
71 
72 	s_mark_end(s);
73 	return tcp_send(This, s);
74 }
75 
76 /* Receive a message on the ISO layer, return code */
77 static STREAM
78 iso_recv_msg(RDPCLIENT * This, uint8 * code, uint8 * rdpver)
79 {
80 	STREAM s;
81 	uint16 length;
82 	uint8 version;
83 
84 	s = tcp_recv(This, NULL, 4);
85 	if (s == NULL)
86 		return NULL;
87 	in_uint8(s, version);
88 	if (rdpver != NULL)
89 		*rdpver = version;
90 	if (version == 3)
91 	{
92 		in_uint8s(s, 1);	/* pad */
93 		in_uint16_be(s, length);
94 	}
95 	else
96 	{
97 		in_uint8(s, length);
98 		if (length & 0x80)
99 		{
100 			length &= ~0x80;
101 			next_be(s, length);
102 		}
103 	}
104 	s = tcp_recv(This, s, length - 4);
105 	if (s == NULL)
106 		return NULL;
107 	if (version != 3)
108 		return s;
109 	in_uint8s(s, 1);	/* hdrlen */
110 	in_uint8(s, *code);
111 	if (*code == ISO_PDU_DT)
112 	{
113 		in_uint8s(s, 1);	/* eot */
114 		return s;
115 	}
116 	in_uint8s(s, 5);	/* dst_ref, src_ref, class */
117 	return s;
118 }
119 
120 /* Initialise ISO transport data packet */
121 STREAM
122 iso_init(RDPCLIENT * This, int length)
123 {
124 	STREAM s;
125 
126 	s = tcp_init(This, length + 7);
127 
128 	if(s == NULL)
129 		return NULL;
130 
131 	s_push_layer(s, iso_hdr, 7);
132 
133 	return s;
134 }
135 
136 /* Send an ISO data PDU */
137 BOOL
138 iso_send(RDPCLIENT * This, STREAM s)
139 {
140 	uint16 length;
141 
142 	s_pop_layer(s, iso_hdr);
143 	length = (uint16)(s->end - s->p);
144 
145 	out_uint8(s, 3);	/* version */
146 	out_uint8(s, 0);	/* reserved */
147 	out_uint16_be(s, length);
148 
149 	out_uint8(s, 2);	/* hdrlen */
150 	out_uint8(s, ISO_PDU_DT);	/* code */
151 	out_uint8(s, 0x80);	/* eot */
152 
153 	return tcp_send(This, s);
154 }
155 
156 /* Receive ISO transport data packet */
157 STREAM
158 iso_recv(RDPCLIENT * This, uint8 * rdpver)
159 {
160 	STREAM s;
161 	uint8 code = 0;
162 
163 	s = iso_recv_msg(This, &code, rdpver);
164 	if (s == NULL)
165 		return NULL;
166 	if (rdpver != NULL)
167 		if (*rdpver != 3)
168 			return s;
169 	if (code != ISO_PDU_DT)
170 	{
171 		error("expected DT, got 0x%x\n", code);
172 		return NULL;
173 	}
174 	return s;
175 }
176 
177 /* Establish a connection up to the ISO layer */
178 BOOL
179 iso_connect(RDPCLIENT * This, char *server, char *cookie)
180 {
181 	uint8 code = 0;
182 
183 	if (!tcp_connect(This, server))
184 		return False;
185 
186 	if (!iso_send_connection_request(This, cookie))
187 		return False;
188 
189 	if (iso_recv_msg(This, &code, NULL) == NULL)
190 		return False;
191 
192 	if (code != ISO_PDU_CC)
193 	{
194 		error("expected CC, got 0x%x\n", code);
195 		tcp_disconnect(This);
196 		return False;
197 	}
198 
199 	return True;
200 }
201 
202 /* Establish a reconnection up to the ISO layer */
203 BOOL
204 iso_reconnect(RDPCLIENT * This, char *server, char *cookie)
205 {
206 	uint8 code = 0;
207 
208 	if (!tcp_connect(This, server))
209 		return False;
210 
211 	if (!iso_send_connection_request(This, cookie)) // BUGBUG should we really pass the cookie here?
212 		return False;
213 
214 	if (iso_recv_msg(This, &code, NULL) == NULL)
215 		return False;
216 
217 	if (code != ISO_PDU_CC)
218 	{
219 		error("expected CC, got 0x%x\n", code);
220 		tcp_disconnect(This);
221 		return False;
222 	}
223 
224 	return True;
225 }
226 
227 /* Disconnect from the ISO layer */
228 BOOL
229 iso_disconnect(RDPCLIENT * This)
230 {
231 	iso_send_msg(This, ISO_PDU_DR);
232 	return tcp_disconnect(This);
233 }
234 
235 /* reset the state to support reconnecting */
236 void
237 iso_reset_state(RDPCLIENT * This)
238 {
239 	tcp_reset_state(This);
240 }
241