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