Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / mcs.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * T.125 Multipoint Communication Service (MCS) Protocol
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include "gcc.h"
21
22 #include "mcs.h"
23 #include "tpdu.h"
24 #include "tpkt.h"
25
26 /**
27  * T.125 MCS is defined in:
28  *
29  * http://www.itu.int/rec/T-REC-T.125-199802-I/
30  * ITU-T T.125 Multipoint Communication Service Protocol Specification
31  */
32
33 /**
34  * Connect-Initial ::= [APPLICATION 101] IMPLICIT SEQUENCE
35  * {
36  *      callingDomainSelector           OCTET_STRING,
37  *      calledDomainSelector            OCTET_STRING,
38  *      upwardFlag                      BOOLEAN,
39  *      targetParameters                DomainParameters,
40  *      minimumParameters               DomainParameters,
41  *      maximumParameters               DomainParameters,
42  *      userData                        OCTET_STRING
43  * }
44  *
45  * DomainParameters ::= SEQUENCE
46  * {
47  *      maxChannelIds                   INTEGER (0..MAX),
48  *      maxUserIds                      INTEGER (0..MAX),
49  *      maxTokenIds                     INTEGER (0..MAX),
50  *      numPriorities                   INTEGER (0..MAX),
51  *      minThroughput                   INTEGER (0..MAX),
52  *      maxHeight                       INTEGER (0..MAX),
53  *      maxMCSPDUsize                   INTEGER (0..MAX),
54  *      protocolVersion                 INTEGER (0..MAX)
55  * }
56  *
57  * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE
58  * {
59  *      result                          Result,
60  *      calledConnectId                 INTEGER (0..MAX),
61  *      domainParameters                DomainParameters,
62  *      userData                        OCTET_STRING
63  * }
64  *
65  * Result ::= ENUMERATED
66  * {
67  *      rt-successful                   (0),
68  *      rt-domain-merging               (1),
69  *      rt-domain-not-hierarchical      (2),
70  *      rt-no-such-channel              (3),
71  *      rt-no-such-domain               (4),
72  *      rt-no-such-user                 (5),
73  *      rt-not-admitted                 (6),
74  *      rt-other-user-id                (7),
75  *      rt-parameters-unacceptable      (8),
76  *      rt-token-not-available          (9),
77  *      rt-token-not-possessed          (10),
78  *      rt-too-many-channels            (11),
79  *      rt-too-many-tokens              (12),
80  *      rt-too-many-users               (13),
81  *      rt-unspecified-failure          (14),
82  *      rt-user-rejected                (15)
83  * }
84  *
85  * ErectDomainRequest ::= [APPLICATION 1] IMPLICIT SEQUENCE
86  * {
87  *      subHeight                       INTEGER (0..MAX),
88  *      subInterval                     INTEGER (0..MAX)
89  * }
90  *
91  * AttachUserRequest ::= [APPPLICATION 10] IMPLICIT SEQUENCE
92  * {
93  * }
94  *
95  * AttachUserConfirm ::= [APPLICATION 11] IMPLICIT SEQUENCE
96  * {
97  *      result                          Result,
98  *      initiator                       UserId OPTIONAL
99  * }
100  *
101  * ChannelJoinRequest ::= [APPLICATION 14] IMPLICIT SEQUENCE
102  * {
103  *      initiator                       UserId,
104  *      channelId                       ChannelId
105  * }
106  *
107  * ChannelJoinConfirm ::= [APPLICATION 15] IMPLICIT SEQUENCE
108  * {
109  *      result                          Result,
110  *      initiator                       UserId,
111  *      requested                       ChannelId,
112  *      channelId                       ChannelId OPTIONAL
113  * }
114  *
115  * SendDataRequest ::= [APPLICATION 25] IMPLICIT SEQUENCE
116  * {
117  *      initiator                       UserId,
118  *      channelId                       ChannelId,
119  *      dataPriority                    DataPriority,
120  *      segmentation                    Segmentation,
121  *      userData                        OCTET_STRING
122  * }
123  *
124  * DataPriority ::= CHOICE
125  * {
126  *      top                             NULL,
127  *      high                            NULL,
128  *      medium                          NULL,
129  *      low                             NULL,
130  *      ...
131  * }
132  *
133  * Segmentation ::= BIT_STRING
134  * {
135  *      begin                           (0),
136  *      end                             (1)
137  * } (SIZE(2))
138  *
139  * SendDataIndication ::= SEQUENCE
140  * {
141  *      initiator                       UserId,
142  *      channelId                       ChannelId,
143  *      reliability                     BOOLEAN,
144  *      domainReferenceID               INTEGER (0..65535) OPTIONAL,
145  *      dataPriority                    DataPriority,
146  *      segmentation                    Segmentation,
147  *      userData                        OCTET_STRING,
148  *      totalDataSize                   INTEGER OPTIONAL,
149  *      nonStandard                     SEQUENCE OF NonStandardParameter OPTIONAL,
150  *      ...
151  * }
152  *
153  */
154
155 static const uint8 callingDomainSelector[1] = "\x01";
156 static const uint8 calledDomainSelector[1] = "\x01";
157
158 /*
159 static const char* const mcs_result_enumerated[] =
160 {
161                 "rt-successful",
162                 "rt-domain-merging",
163                 "rt-domain-not-hierarchical",
164                 "rt-no-such-channel",
165                 "rt-no-such-domain",
166                 "rt-no-such-user",
167                 "rt-not-admitted",
168                 "rt-other-user-id",
169                 "rt-parameters-unacceptable",
170                 "rt-token-not-available",
171                 "rt-token-not-possessed",
172                 "rt-too-many-channels",
173                 "rt-too-many-tokens",
174                 "rt-too-many-users",
175                 "rt-unspecified-failure",
176                 "rt-user-rejected"
177 };
178 */
179
180 /**
181  * Read a DomainMCSPDU header.
182  * @param s stream
183  * @param domainMCSPDU DomainMCSPDU type
184  * @param length TPKT length
185  * @return
186  */
187
188 boolean mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU, uint16* length)
189 {
190         uint8 choice;
191         enum DomainMCSPDU MCSPDU;
192
193         *length = tpkt_read_header(s);
194
195         if (tpdu_read_data(s) == 0)
196                 return false;
197
198         MCSPDU = *domainMCSPDU;
199         per_read_choice(s, &choice);
200         *domainMCSPDU = (choice >> 2);
201
202         if (*domainMCSPDU != MCSPDU)
203                 return false;
204
205         return true;
206 }
207
208 /**
209  * Write a DomainMCSPDU header.
210  * @param s stream
211  * @param domainMCSPDU DomainMCSPDU type
212  * @param length TPKT length
213  */
214
215 void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, uint16 length, uint8 options)
216 {
217         tpkt_write_header(s, length);
218         tpdu_write_data(s);
219         per_write_choice(s, (domainMCSPDU << 2) | options);
220 }
221
222 /**
223  * Initialize MCS Domain Parameters.
224  * @param domainParameters domain parameters
225  * @param maxChannelIds max channel ids
226  * @param maxUserIds max user ids
227  * @param maxTokenIds max token ids
228  * @param maxMCSPDUsize max MCS PDU size
229  */
230
231 static void mcs_init_domain_parameters(DomainParameters* domainParameters,
232                 uint32 maxChannelIds, uint32 maxUserIds, uint32 maxTokenIds, uint32 maxMCSPDUsize)
233 {
234         domainParameters->maxChannelIds = maxChannelIds;
235         domainParameters->maxUserIds = maxUserIds;
236         domainParameters->maxTokenIds = maxTokenIds;
237         domainParameters->maxMCSPDUsize = maxMCSPDUsize;
238
239         domainParameters->numPriorities = 1;
240         domainParameters->minThroughput = 0;
241         domainParameters->maxHeight = 1;
242         domainParameters->protocolVersion = 2;
243 }
244
245 /**
246  * Read MCS Domain Parameters.
247  * @param s stream
248  * @param domainParameters domain parameters
249  */
250
251 boolean mcs_read_domain_parameters(STREAM* s, DomainParameters* domainParameters)
252 {
253         int length;
254         ber_read_sequence_tag(s, &length);
255         ber_read_integer(s, &(domainParameters->maxChannelIds));
256         ber_read_integer(s, &(domainParameters->maxUserIds));
257         ber_read_integer(s, &(domainParameters->maxTokenIds));
258         ber_read_integer(s, &(domainParameters->numPriorities));
259         ber_read_integer(s, &(domainParameters->minThroughput));
260         ber_read_integer(s, &(domainParameters->maxHeight));
261         ber_read_integer(s, &(domainParameters->maxMCSPDUsize));
262         ber_read_integer(s, &(domainParameters->protocolVersion));
263
264         return true;
265 }
266
267 /**
268  * Write MCS Domain Parameters.
269  * @param s stream
270  * @param domainParameters domain parameters
271  */
272
273 void mcs_write_domain_parameters(STREAM* s, DomainParameters* domainParameters)
274 {
275         int length;
276         STREAM* tmps;
277
278         tmps = stream_new(stream_get_size(s));
279         ber_write_integer(tmps, domainParameters->maxChannelIds);
280         ber_write_integer(tmps, domainParameters->maxUserIds);
281         ber_write_integer(tmps, domainParameters->maxTokenIds);
282         ber_write_integer(tmps, domainParameters->numPriorities);
283         ber_write_integer(tmps, domainParameters->minThroughput);
284         ber_write_integer(tmps, domainParameters->maxHeight);
285         ber_write_integer(tmps, domainParameters->maxMCSPDUsize);
286         ber_write_integer(tmps, domainParameters->protocolVersion);
287
288         length = stream_get_length(tmps);
289         ber_write_sequence_tag(s, length);
290         stream_write(s, stream_get_head(tmps), length);
291         stream_free(tmps);
292 }
293
294 /**
295  * Print MCS Domain Parameters.
296  * @param domainParameters domain parameters
297  */
298
299 void mcs_print_domain_parameters(DomainParameters* domainParameters)
300 {
301         printf("DomainParameters {\n");
302         printf("\tmaxChannelIds:%d\n", domainParameters->maxChannelIds);
303         printf("\tmaxUserIds:%d\n", domainParameters->maxUserIds);
304         printf("\tmaxTokenIds:%d\n", domainParameters->maxTokenIds);
305         printf("\tnumPriorities:%d\n", domainParameters->numPriorities);
306         printf("\tminThroughput:%d\n", domainParameters->minThroughput);
307         printf("\tmaxHeight:%d\n", domainParameters->maxHeight);
308         printf("\tmaxMCSPDUsize:%d\n", domainParameters->maxMCSPDUsize);
309         printf("\tprotocolVersion:%d\n", domainParameters->protocolVersion);
310         printf("}\n");
311 }
312
313 /**
314  * Read an MCS Connect Initial PDU.\n
315  * @msdn{cc240508}
316  * @param mcs MCS module
317  * @param s stream
318  */
319
320 boolean mcs_recv_connect_initial(rdpMcs* mcs, STREAM* s)
321 {
322         int length;
323         boolean upwardFlag;
324
325         tpkt_read_header(s);
326
327         if (tpdu_read_data(s) == 0)
328                 return false;
329
330         if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))
331                 return false;
332
333         /* callingDomainSelector (OCTET_STRING) */
334         if (!ber_read_octet_string(s, &length))
335                 return false;
336         stream_seek(s, length);
337
338         /* calledDomainSelector (OCTET_STRING) */
339         if (!ber_read_octet_string(s, &length))
340                 return false;
341         stream_seek(s, length);
342
343         /* upwardFlag (BOOLEAN) */
344         if (!ber_read_boolean(s, &upwardFlag))
345                 return false;
346
347         /* targetParameters (DomainParameters) */
348         mcs_read_domain_parameters(s, &mcs->targetParameters);
349
350         /* minimumParameters (DomainParameters) */
351         mcs_read_domain_parameters(s, &mcs->minimumParameters);
352
353         /* maximumParameters (DomainParameters) */
354         mcs_read_domain_parameters(s, &mcs->maximumParameters);
355
356         if (!ber_read_octet_string(s, &length))
357                 return false;
358
359         if (!gcc_read_conference_create_request(s, mcs->transport->settings))
360                 return false;
361
362         return true;
363 }
364
365 /**
366  * Write an MCS Connect Initial PDU.\n
367  * @msdn{cc240508}
368  * @param s stream
369  * @param mcs MCS module
370  * @param user_data GCC Conference Create Request
371  */
372
373 void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data)
374 {
375         int length;
376         STREAM* tmps;
377
378         tmps = stream_new(stream_get_size(s));
379
380         /* callingDomainSelector (OCTET_STRING) */
381         ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector));
382
383         /* calledDomainSelector (OCTET_STRING) */
384         ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector));
385
386         /* upwardFlag (BOOLEAN) */
387         ber_write_boolean(tmps, true);
388
389         /* targetParameters (DomainParameters) */
390         mcs_write_domain_parameters(tmps, &mcs->targetParameters);
391
392         /* minimumParameters (DomainParameters) */
393         mcs_write_domain_parameters(tmps, &mcs->minimumParameters);
394
395         /* maximumParameters (DomainParameters) */
396         mcs_write_domain_parameters(tmps, &mcs->maximumParameters);
397
398         /* userData (OCTET_STRING) */
399         ber_write_octet_string(tmps, user_data->data, stream_get_length(user_data));
400
401         length = stream_get_length(tmps);
402         /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */
403         ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);
404         stream_write(s, stream_get_head(tmps), length);
405         stream_free(tmps);
406 }
407
408 /**
409  * Write an MCS Connect Response PDU.\n
410  * @msdn{cc240508}
411  * @param s stream
412  * @param mcs MCS module
413  * @param user_data GCC Conference Create Response
414  */
415
416 void mcs_write_connect_response(STREAM* s, rdpMcs* mcs, STREAM* user_data)
417 {
418         int length;
419         STREAM* tmps;
420
421         tmps = stream_new(stream_get_size(s));
422         ber_write_enumerated(tmps, 0, MCS_Result_enum_length);
423         ber_write_integer(tmps, 0); /* calledConnectId */
424         mcs->domainParameters = mcs->targetParameters;
425         mcs_write_domain_parameters(tmps, &(mcs->domainParameters));
426         /* userData (OCTET_STRING) */
427         ber_write_octet_string(tmps, user_data->data, stream_get_length(user_data));
428
429         length = stream_get_length(tmps);
430         ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);
431         stream_write(s, stream_get_head(tmps), length);
432         stream_free(tmps);
433 }
434
435 /**
436  * Send MCS Connect Initial.\n
437  * @msdn{cc240508}
438  * @param mcs mcs module
439  */
440
441 boolean mcs_send_connect_initial(rdpMcs* mcs)
442 {
443         STREAM* s;
444         int length;
445         uint8 *bm, *em;
446         STREAM* gcc_CCrq;
447         STREAM* client_data;
448         int status;
449
450         client_data = stream_new(512);
451         gcc_write_client_data_blocks(client_data, mcs->transport->settings);
452
453         gcc_CCrq = stream_new(512);
454         gcc_write_conference_create_request(gcc_CCrq, client_data);
455         length = stream_get_length(gcc_CCrq) + 7;
456
457         s = transport_send_stream_init(mcs->transport, 1024);
458         stream_get_mark(s, bm);
459         stream_seek(s, 7);
460
461         mcs_write_connect_initial(s, mcs, gcc_CCrq);
462         stream_get_mark(s, em);
463         length = (em - bm);
464         stream_set_mark(s, bm);
465
466         tpkt_write_header(s, length);
467         tpdu_write_data(s);
468         stream_set_mark(s, em);
469
470         status = transport_write(mcs->transport, s);
471
472         stream_free(gcc_CCrq);
473         stream_free(client_data);
474
475         return (status < 0 ? false : true);
476 }
477
478 /**
479  * Read MCS Connect Response.\n
480  * @msdn{cc240501}
481  * @param mcs mcs module
482  */
483
484 boolean mcs_recv_connect_response(rdpMcs* mcs, STREAM* s)
485 {
486         int length;
487         uint8 result;
488         uint32 calledConnectId;
489
490         tpkt_read_header(s);
491
492         if (tpdu_read_data(s) == 0)
493                 return false;
494
495         ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length);
496         ber_read_enumerated(s, &result, MCS_Result_enum_length);
497         ber_read_integer(s, &calledConnectId);
498
499         if (!mcs_read_domain_parameters(s, &(mcs->domainParameters)))
500                 return false;
501
502         ber_read_octet_string(s, &length);
503
504         if (!gcc_read_conference_create_response(s, mcs->transport->settings))
505         {
506                 printf("mcs_recv_connect_response: gcc_read_conference_create_response failed\n");
507                 return false;
508         }
509
510         return true;
511 }
512
513 /**
514  * Send MCS Connect Response.\n
515  * @msdn{cc240501}
516  * @param mcs mcs module
517  */
518
519 boolean mcs_send_connect_response(rdpMcs* mcs)
520 {
521         STREAM* s;
522         int length;
523         uint8 *bm, *em;
524         STREAM* gcc_CCrsp;
525         STREAM* server_data;
526
527         server_data = stream_new(512);
528         gcc_write_server_data_blocks(server_data, mcs->transport->settings);
529
530         gcc_CCrsp = stream_new(512);
531         gcc_write_conference_create_response(gcc_CCrsp, server_data);
532         length = stream_get_length(gcc_CCrsp) + 7;
533
534         s = transport_send_stream_init(mcs->transport, 1024);
535         stream_get_mark(s, bm);
536         stream_seek(s, 7);
537
538         mcs_write_connect_response(s, mcs, gcc_CCrsp);
539         stream_get_mark(s, em);
540         length = (em - bm);
541         stream_set_mark(s, bm);
542
543         tpkt_write_header(s, length);
544         tpdu_write_data(s);
545         stream_set_mark(s, em);
546
547         transport_write(mcs->transport, s);
548
549         stream_free(gcc_CCrsp);
550         stream_free(server_data);
551
552         return true;
553 }
554
555 /**
556  * Read MCS Erect Domain Request.\n
557  * @msdn{cc240523}
558  * @param mcs
559  * @param s stream
560  */
561
562 boolean mcs_recv_erect_domain_request(rdpMcs* mcs, STREAM* s)
563 {
564         uint16 length;
565         enum DomainMCSPDU MCSPDU;
566
567         MCSPDU = DomainMCSPDU_ErectDomainRequest;
568         if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
569                 return false;
570
571         return true;
572 }
573
574 /**
575  * Send MCS Erect Domain Request.\n
576  * @msdn{cc240523}
577  * @param mcs
578  */
579
580 boolean mcs_send_erect_domain_request(rdpMcs* mcs)
581 {
582         STREAM* s;
583         uint16 length = 12;
584         s = transport_send_stream_init(mcs->transport, length);
585
586         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0);
587
588         per_write_integer(s, 0); /* subHeight (INTEGER) */
589         per_write_integer(s, 0); /* subInterval (INTEGER) */
590
591         if (transport_write(mcs->transport, s) < 0)
592                 return false;
593
594         return true;
595 }
596
597 /**
598  * Read MCS Attach User Request.\n
599  * @msdn{cc240524}
600  * @param mcs mcs module
601  * @param s stream
602  */
603
604 boolean mcs_recv_attach_user_request(rdpMcs* mcs, STREAM* s)
605 {
606         uint16 length;
607         enum DomainMCSPDU MCSPDU;
608
609         MCSPDU = DomainMCSPDU_AttachUserRequest;
610         if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
611                 return false;
612
613         return true;
614 }
615
616 /**
617  * Send MCS Attach User Request.\n
618  * @msdn{cc240524}
619  * @param mcs mcs module
620  */
621
622 boolean mcs_send_attach_user_request(rdpMcs* mcs)
623 {
624         STREAM* s;
625         uint16 length = 8;
626         s = transport_send_stream_init(mcs->transport, length);
627
628         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0);
629
630         if (transport_write(mcs->transport, s) < 0)
631                 return false;
632
633         return true;
634 }
635
636 /**
637  * Read MCS Attach User Confirm.\n
638  * @msdn{cc240525}
639  * @param mcs mcs module
640  */
641
642 boolean mcs_recv_attach_user_confirm(rdpMcs* mcs, STREAM* s)
643 {
644         uint16 length;
645         uint8 result;
646         enum DomainMCSPDU MCSPDU;
647
648         MCSPDU = DomainMCSPDU_AttachUserConfirm;
649         if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
650                 return false;
651
652         per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */
653         per_read_integer16(s, &(mcs->user_id), MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
654
655         return true;
656 }
657
658 /**
659  * Send MCS Attach User Confirm.\n
660  * @msdn{cc240525}
661  * @param mcs mcs module
662  */
663
664 boolean mcs_send_attach_user_confirm(rdpMcs* mcs)
665 {
666         STREAM* s;
667         uint16 length = 11;
668         
669         s = transport_send_stream_init(mcs->transport, length);
670
671         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2);
672
673         per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
674         mcs->user_id = 1002;
675         per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
676
677         transport_write(mcs->transport, s);
678
679         return true;
680 }
681
682 /**
683  * Read MCS Channel Join Request.\n
684  * @msdn{cc240526}
685  * @param mcs mcs module
686  * @param s stream
687  */
688
689 boolean mcs_recv_channel_join_request(rdpMcs* mcs, STREAM* s, uint16* channel_id)
690 {
691         uint16 length;
692         enum DomainMCSPDU MCSPDU;
693         uint16 user_id;
694
695         MCSPDU = DomainMCSPDU_ChannelJoinRequest;
696         if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
697                 return false;
698
699         if (!per_read_integer16(s, &user_id, MCS_BASE_CHANNEL_ID))
700                 return false;
701         if (user_id != mcs->user_id)
702                 return false;
703         if (!per_read_integer16(s, channel_id, 0))
704                 return false;
705
706         return true;
707 }
708
709 /**
710  * Send MCS Channel Join Request.\n
711  * @msdn{cc240526}
712  * @param mcs mcs module
713  * @param channel_id channel id
714  */
715
716 boolean mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id)
717 {
718         STREAM* s;
719         uint16 length = 12;
720         s = transport_send_stream_init(mcs->transport, 12);
721
722         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0);
723
724         per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID);
725         per_write_integer16(s, channel_id, 0);
726
727         if (transport_write(mcs->transport, s) < 0)
728                 return false;
729
730         return true;
731 }
732
733 /**
734  * Read MCS Channel Join Confirm.\n
735  * @msdn{cc240527}
736  * @param mcs mcs module
737  */
738
739 boolean mcs_recv_channel_join_confirm(rdpMcs* mcs, STREAM* s, uint16* channel_id)
740 {
741         uint16 length;
742         uint8 result;
743         uint16 initiator;
744         uint16 requested;
745         enum DomainMCSPDU MCSPDU;
746
747         MCSPDU = DomainMCSPDU_ChannelJoinConfirm;
748         if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
749                 return false;
750
751         per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */
752         per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
753         per_read_integer16(s, &requested, 0); /* requested (ChannelId) */
754         per_read_integer16(s, channel_id, 0); /* channelId */
755
756         return true;
757 }
758
759 /**
760  * Send MCS Channel Join Confirm.\n
761  * @msdn{cc240527}
762  * @param mcs mcs module
763  */
764
765 boolean mcs_send_channel_join_confirm(rdpMcs* mcs, uint16 channel_id)
766 {
767         STREAM* s;
768         uint16 length = 15;
769         s = transport_send_stream_init(mcs->transport, 15);
770
771         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2);
772
773         per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */
774         per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
775         per_write_integer16(s, channel_id, 0); /* requested (ChannelId) */
776         per_write_integer16(s, channel_id, 0); /* channelId */
777
778         transport_write(mcs->transport, s);
779
780         return true;
781 }
782
783 /**
784  * Send MCS Disconnect Provider Ultimatum PDU.\n
785  * @param mcs mcs module
786  */
787
788 boolean mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)
789 {
790         STREAM* s;
791         uint16 length = 9;
792         s = transport_send_stream_init(mcs->transport, 9);
793
794         mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1);
795
796         per_write_enumerated(s, 0, 0); /* reason */
797
798         transport_write(mcs->transport, s);
799
800         return true;
801 }
802
803 /**
804  * Instantiate new MCS module.
805  * @param transport transport
806  * @return new MCS module
807  */
808
809 rdpMcs* mcs_new(rdpTransport* transport)
810 {
811         rdpMcs* mcs;
812
813         mcs = (rdpMcs*) xzalloc(sizeof(rdpMcs));
814
815         if (mcs != NULL)
816         {
817                 mcs->transport = transport;
818                 mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);
819                 mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);
820                 mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);
821         }
822
823         return mcs;
824 }
825
826 /**
827  * Free MCS module.
828  * @param mcs MCS module to be freed
829  */
830
831 void mcs_free(rdpMcs* mcs)
832 {
833         if (mcs != NULL)
834         {
835                 xfree(mcs);
836         }
837 }