TPlayer.C
1// -*- C++ -*-
2
3// Copyright (c) 2006-2010, Isode Limited, London, England.
4// All rights reserved.
5//
6// Acquisition and use of this software and related materials for any
7// purpose requires a written licence agreement from Isode Limited,
8// or a written licence from an organisation licenced by Isode Limited
9// to grant such a licence.
10
11// TPlayer.C
12//
13// Implementation of Transport Class 0 and 2 (for RFC 2126 et. al)
14//
15// @VERSION@
16
17#include "../include/TPlayer.h"
18
19#include "../include/EventSvc.h"
20
21#include <isode/messages/ioevent.h>
22
23// Default TPDU max sizes
24
25#define MINMAXTPDU 128
26#define MAXTPDU0 2048
27#define MAXTPDU2 8192
28
29namespace Transport {
30#if defined(__clang__)
31 const unsigned TPbuffer::TPBINC;
32#endif
33
34 enum TPPDUcode {
35 PDU_CR = 0xE0,
36 PDU_CC = 0xD0,
37 PDU_DR = 0x80,
38 PDU_DC = 0xC0,
39 PDU_DT = 0xF0,
40 PDU_ED = 0x10,
41 PDU_AK = 0x60,
42 PDU_EA = 0x20,
43 PDU_RJ = 0x50,
44 PDU_ER = 0x70
45 };
46
47 enum PARAMcode {
48 PARAM_tpdusize = 0xC0,
49 PARAM_calling_tsel = 0xC1, // CR
50 PARAM_invalid_tpdu = 0xC1, // ER
51 PARAM_called_tsel = 0xC2, // CR
52 PARAM_respond_tsel = 0xC2, // CC
53 PARAM_checksum = 0xC3,
54 PARAM_version = 0xC4,
55 PARAM_protection = 0xC5,
56 PARAM_additional = 0xC6,
57 PARAM_altclasses = 0xC7,
58 PARAM_acktime = 0x85,
59 PARAM_residerr = 0x86,
60 PARAM_priority = 0x87,
61 PARAM_transitdelay = 0x88,
62 PARAM_throughput = 0x89,
63 PARAM_sequenceno = 0x8A, // in AK
64 PARAM_reasstime = 0x8B,
65 PARAM_flowctrl = 0x8C, // in AK
66 PARAM_selectack = 0x8F, // in AK
67 PARAM_addinfo = 0xE0, // in DR
68 PARAM_prefmaxtpdu = 0xF0,
69 PARAM_inacttime = 0xF2,
70
71 EOT_FLAG = 0x80
72 };
73
74 pthread_mutex_t Layer::refmutex = PTHREAD_MUTEX_INITIALIZER;
75 unsigned Layer::refvalue = 0;
76
77 Layer::~Layer()
78 {
79 free (connect.data);
80 }
81
82 // TCONreq
83 void Layer::Deliver (ConnectRequest *req)
84 {
85 if ( state != CLOSED ) {
86 // X.224 A.2.3 (a)
87 LOG_DEBUG (("TConreq in state %d - ignored", state));
88 return;
89 }
90
91 if ( provider->GetUser() == 0 ) {
92 InternalError (DR_nosession, "No user for CR");
93 return;
94 }
95
96 connect = *req; // struct copy
97
98 if ( req->data != 0 && req->cc > 0 ) {
99 connect.data = (char *) malloc (req->cc);
100 if ( connect.data != 0 )
101 memcpy (connect.data, req->data, req->cc);
102 } else {
103 connect.data = 0;
104 connect.cc = 0;
105 }
106
107 // Check details
108
109 DisconnectIndication disind;
110
111 // Need called network address
112 if ( connect.called.ta_addr.na_addrlen == 0 ) {
113 MSG_Tsap_NoNSAPAddress_SET (&disind.msg);
114 TDISind (disind);
115 return;
116 }
117
118 // Only support classes 0 and 2
119 // If none specified, then use class 0
120 if ( classes & ~(TP_CLASS_0|TP_CLASS_2) ) {
121 MSG_Tsap_Negotiation_SET (&disind.msg);
122 TDISind (disind);
123 return;
124 }
125
126 if ( classes == 0 )
127 classes = TP_CLASS_0;
128
129 if ( maxtpdu == 0 ) {
130 maxtpdu =
131 ( classes & TP_CLASS_2 ) ? MAXTPDU2 : MAXTPDU0;
132
133 } else {
134 // Can only set MAX TPDU in multiples of 128 bytes.
135 maxtpdu &= ~ 0x7FU;
136 }
137
138 if ( maxtpdu < MINMAXTPDU || maxtpdu > MAXTPDU2 ) {
139 MSG_Tsap_BadMaxTPDUsize_SET (&disind.msg, maxtpdu);
140 TDISind (disind);
141 return;
142 }
143
144 LOG_DEBUG (("TP %p: TCONreq -> WFNC", this));
145 state = WFNC;
146
147 net->ConnectRequest (connect.calling.ta_addr, connect.called.ta_addr);
148 }
149
150 //---------------
151 // TCONresp
152 void Layer::Deliver (ConnectResponse *req)
153 {
154 if ( state != WFTRESP ) {
155 // X.224 A.2.3 (a)
156 LOG_DEBUG (("Ignoring TCONresp in state %d", state));
157 return;
158 }
159
160 // Must have dealt with any connect data by now.
161 free (connect.data);
162 connect.data = 0;
163 connect.cc = 0;
164
165 if ( req->responding.ta_selectlen > 0 ) {
166 memcpy (connect.called.ta_selector,
167 req->responding.ta_selector,
168 req->responding.ta_selectlen);
169 connect.called.ta_selectlen = req->responding.ta_selectlen;
170 }
171
172 LOG_DEBUG (("TP %p: TCONresp -> OPEN", this));
173 state = OPEN;
174 makeCC ();
175 }
176
177 //---------------
178 // TDTreq/TEXreq
179 void Layer::Deliver (DataRequest *req)
180 {
181 if ( state != OPEN ) {
182 // X.224 A.2.3 (a)
183 LOG_DEBUG (("Ignoring TDTreq in state %d", state));
184 return;
185 }
186
187 // TEXreq not supported
188 if ( req->expedited ) {
189 InternalError (DR_protocol, "Expedited data not supported");
190 return;
191 }
192
193 makeDT (req->uv, req->eot);
194 }
195
196 //---------------
197 // TDISreq
198 void Layer::Deliver (DisconnectRequest *data)
199 {
200 switch ( state ) {
201 case CLOSED:
202 case CLOSING:
203 case WFCR:
204 case WBCL:
205 // X.224 A.2.3 (a)
206 LOG_DEBUG (("Ignoring TDISreq in state %d", state));
207 break;
208
209 case WFNC:
210 state = CLOSED;
211 break;
212
213 case WFCC:
214 if ( classes & TP_CLASS_0 ) {
215 net->DisconnectRequest();
216 state = CLOSED;
217 } else {
218 state = WBCL;
219 }
220 break;
221
222 case WFTRESP:
223 makeDR (data->reason, data->data, data->cc);
224 state = CLOSED;
225 break;
226
227 case OPEN:
228 if ( classes & TP_CLASS_0 ) {
229 net->DisconnectRequest();
230 state = CLOSED;
231 } else {
232 makeDR (data->reason, data->data, data->cc);
233 state = CLOSING;
234 }
235 break;
236 }
237 // Tell the TSuser that we will not send it anything else
238 DisconnectIndication disind;
239 MSG_Tsap_NormalDisconnect_SET (&disind.msg);
240 TDISind (disind);
241 }
242
243 //---------------
244 void Layer::NetworkRead (struct qbuf *qb)
245 {
246 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
247
248 LOG_DEBUG (("NetworkRead: %ld (%d)", (long)qb->qb_len, *dp));
249
250 // Check fixed + variable part is within the overall length
251 // (Note: the LI field does not include itself)
252 if ( *dp >= qb->qb_len || *dp < 2 ) {
253 MSG_Tsap_RejectUnspecified_LOG ("Bad length field in TPKT");
254 ProtocolError (qb, 1, Reject_NotSpecified);
255 return;
256 }
257
258 // Only the top 4 bits determine TPDU type
259 switch ( dp[1] & 0xF0 ) {
260 case 0xF0: // DT
261 getDT (qb);
262 return; // As getDT is responsible for qbuf
263
264 case PDU_CR:
265 getCR (qb);
266 break;
267
268 case PDU_CC:
269 getCC (qb);
270 break;
271
272 case PDU_DR:
273 getDR (qb);
274 break;
275
276 case PDU_DC:
277 getDC (qb);
278 break;
279
280 case PDU_ED:
281 getED (qb);
282 return; // As getED is responsible for qbuf
283
284 case PDU_ER:
285 getER (qb);
286 break;
287
288 case PDU_AK:
289 case PDU_EA:
290 case PDU_RJ:
291 // Ignore known but irrelevant TPDUs
292 LOG_DEBUG (("Ignoring TPDU with type 0x%2.2X", dp[1]));
293 break;
294
295 default:
296 // Unknown TPDU, protocol error
297 MSG_Tsap_RejectBadType_LOG (dp[1]);
298 ProtocolError (qb, 2, Reject_InvalidTPDUtype);
299 break;
300 }
301
302 qb_free (qb);
303 }
304
305 // Network disconnect indication
306 bool Layer::NetworkStatus (MSGstruct *msp)
307 {
308 switch (MSG2LEVEL(msp)) {
309 case MSGLEVEL_CRITICAL:
310 case MSGLEVEL_FATAL:
311 case MSGLEVEL_ERROR:
312 // NRSTind (in effect)
313 // Will pass network layer error upwards
314 break;
315
316 case MSGLEVEL_NOTICE:
317 switch ( MSG2msgid_err (msp) ) {
318 case MSG_IOevent_ConnectionClosed:
319 // NDISind
320 if ( classes & TP_CLASS_0 )
321 MSG_Tsap_NormalDisconnect_SET (msp);
322 else
323 MSG_Tsap_NotSpecified_SET(msp);
324 break;
325
326 default:
327 LOGmessage (msp);
328 return false;
329 }
330 break;
331
332 case MSGLEVEL_SUCCESS:
333 switch ( MSG2msgid_err (msp) ) {
334 case MSG_IOevent_Connected:
335 // NCONconf
336 if ( state == WFNC ) {
337 LOG_DEBUG (("TP %p NCONconf -> WFCC", this));
338 state = WFCC;
339 makeCR();
340
341 } // else ignore it
342 return false;
343
344 default:
345 LOGmessage (msp);
346 return false;
347 }
348
349 default:
350 LOGmessage (msp);
351 return false;
352 }
353
354 // Closing down
355 if ( provider->GetUser() ) {
356 switch ( state ) {
357 default:
358 {
359 DisconnectIndication disind;
360 disind.msg = *msp;
361 TDISind (disind);
362 break;
363 }
364
365 case WFCR:
366 // Inbound connection failed before being set up
367 // User is listener so will not call Done()
368 LOGmessage (msp);
369 provider->Done();
370 break;
371
372
373 case WBCL:
374 case CLOSING:
375 // User should know that closing
376 break;
377 }
378
379 } else {
380 LOGmessage (msp);
381 }
382
383 // network should already be closed
384 net = 0;
385
386 state = CLOSED;
387
388 return true;
389 }
390
391 //-------------
392 void Layer::ProtocolError (struct qbuf *qb,
393 int poffset,
394 enum RejectCause cause)
395 {
396 if ( net != 0 ) {
397 makeER (cause, reinterpret_cast<u_char *>(qb->qb_data), poffset);
398 CloseNetwork();
399 }
400 }
401
402
403 //-------------
404 void Layer::SendUserDR (enum DRreason reason, const char *text)
405 {
406 DisconnectIndication disind;
407
408 switch ( reason ) {
409 case DR_waitclose:
410 case DR_notspecified:
411 MSG_Tsap_NotSpecified_SET (&disind.msg);
412 break;
413
414 case DR_congestion:
415 MSG_Tsap_Congestion_SET (&disind.msg);
416 break;
417
418 case DR_nosession:
419 MSG_Tsap_NoSession_SET (&disind.msg);
420 break;
421
422 case DR_address:
423 MSG_Tsap_AddressUnknown_SET (&disind.msg);
424 break;
425
426 case DR_normal:
427 MSG_Tsap_NormalDisconnect_SET (&disind.msg);
428 break;
429
430 case DR_remcongested:
431 MSG_Tsap_RemoteCongestion_SET (&disind.msg);
432 break;
433
434 case DR_negotiation:
435 MSG_Tsap_Negotiation_SET (&disind.msg);
436 break;
437
438 case DR_duplicate:
439 MSG_Tsap_Duplicate_SET (&disind.msg);
440 break;
441
442 case DR_mismatched:
443 MSG_Tsap_Mismatch_SET (&disind.msg);
444 break;
445
446 case DR_protocol:
447 MSG_Tsap_Protocol_SET (&disind.msg);
448 break;
449
450 case DR_reference:
451 MSG_Tsap_Overflow_SET (&disind.msg);
452 break;
453
454 case DR_network:
455 MSG_Tsap_NetRefused_SET (&disind.msg);
456 break;
457
458 case DR_invalidlen:
459 MSG_Tsap_InvalidLength_SET (&disind.msg);
460 break;
461 }
462
463 if ( text != 0 ) {
464 MSGstruct addmsg;
465
466 MSG_Tsap_UserData_SET (&addmsg, text);
467
468 MSGappend (&disind.msg, &addmsg);
469 }
470
471 if ( provider->GetUser() == 0 ) {
472 // If no user, then log the message here
473 LOGmessage (&disind.msg);
474 } else {
475 TDISind (disind);
476 }
477 }
478
479 //-------------
480 void Layer::InternalError (enum DRreason reason, const char *text)
481 {
482 if ( state != CLOSED && net != 0 ) {
483 if ( classes & TP_CLASS_0 ) {
484 net->DisconnectRequest();
485 net = 0;
486 state = CLOSED;
487 } else {
488 makeDR (reason, 0, 0);
489 state = CLOSING;
490 }
491 }
492
493 SendUserDR (reason, text);
494 }
495
496 //-------------
497 static void SaveAddr (const tsapADDR &ta, char *selbuf, char *addbuf)
498 {
499 if ( ta.ta_selectlen > 0 )
500 selbuf[explode (selbuf,
501 (const u_char *)ta.ta_selector,
502 ta.ta_selectlen)] = '\0';
503 else
504 strcpy (selbuf, "0");
505
506 addbuf[explode (addbuf,
507 (const u_char *)ta.ta_addr.na_address,
508 ta.ta_addr.na_addrlen)] = '\0';
509 }
510
511 //-------------
512 static void RestoreAddr (tsapADDR &ta, const char *selbuf, const char *addbuf)
513 {
514 ta.ta_selectlen = implode ((u_char *)ta.ta_selector,
515 selbuf,
516 strlen(selbuf));
517
518 ta.ta_addr.na_addrlen = implode ((u_char *)ta.ta_addr.na_address,
519 addbuf,
520 strlen(addbuf));
521 }
522
523 //-------------
524 void Layer::GetSaveInfo (char *buffer, size_t buflen)
525 {
526 char callingsel[2*TSSIZE+1];
527 char callingadd[2*NASIZE+1];
528 char calledsel[2*TSSIZE+1];
529 char calledadd[2*NASIZE+1];
530
531 SaveAddr (connect.calling, callingsel, callingadd);
532 SaveAddr (connect.called, calledsel, calledadd);
533
534 if ( snprintf (buffer, buflen,
535 "%u:%u:%u:%u:%d:%d:%s.%s:%s.%s",
536 classes, maxtpdu, srcref, dstref,
537 useprefsize, state,
538 callingsel, callingadd,
539 calledsel, calledadd) < 0 )
540 // buffer filled on Windows; thus not NUL terminated
541 buffer[buflen-1] = '\0';
542 }
543
544 //-------------
545 bool Layer::SetSaveInfo (const char *buffer)
546 {
547 int istate;
548 int iuse;
549
550 char callingsel[2*TSSIZE+1];
551 char callingadd[2*NASIZE+1];
552 char calledsel[2*TSSIZE+1];
553 char calledadd[2*NASIZE+1];
554
555 if ( sscanf (buffer, "%u:%u:%u:%u:%d:%d"
556 ":%[0-9A-Fa-f].%[0-9A-Fa-f]"
557 ":%[0-9A-Fa-f].%[0-9A-Fa-f]",
558 &classes, &maxtpdu, &srcref, &dstref,
559 &iuse, &istate,
560 callingsel, callingadd,
561 calledsel, calledadd) != 10 )
562 return false;
563
564 RestoreAddr (connect.calling, callingsel, callingadd);
565 RestoreAddr (connect.called, calledsel, calledadd);
566
567 state = static_cast<State>(istate);
568 useprefsize = (iuse != 0);
569
570 return true;
571 }
572
573 //--------------------------------------------------------------------
574 // TPDU handling
575
576 void Layer::getCR (struct qbuf *qb)
577 {
578 if ( state != WFCR ) {
579 LOG_DEBUG (("Ignore CR in state %d", state));
580 return;
581 }
582
583 if ( provider->GetUser() == 0 ) {
584 MSG_Tsap_NoUser_LOG("Layer:getCR");
585 ProtocolError (qb, 1, Reject_NotSpecified);
586 return;
587 }
588
589 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
590
591 if ( dp[0] < 6 ) {
592 MSG_Tsap_RejectUnspecified_LOG ("Bad length field in CR");
593 ProtocolError (qb, 1, Reject_NotSpecified);
594 return;
595 }
596
597 if ( dp[2] != 0 || dp[3] != 0 ) {
598 MSG_Tsap_RejectBadValue_LOG ("dst-ref");
599 ProtocolError (qb, 4, Reject_InvalidParameterValue);
600 return;
601 }
602
603 // Their SRC-REF is our DST-REF
604 dstref = (dp[4]<<8) | dp[5];
605
606 classes = (1U<<(dp[6]>>4));
607
608 unsigned options = dp[6] & 0xF;
609
610 if ( options & 0xC ) {
611 MSG_Tsap_RejectBadValue_LOG ("options");
612 ProtocolError (qb, 7, Reject_InvalidParameterValue);
613 return;
614 }
615
616 // Initialize non-network fields in connect data structure
617 connect.calling.ta_selectlen = 0;
618 connect.called.ta_selectlen = 0;
619 connect.expedited = false;
620 connect.data = 0;
621 connect.cc = 0;
622 memset (&connect.qos, 0, sizeof (connect.qos));
623
624 const u_char *pp = dp + 7;
625 const u_char *ud = dp + dp[0] + 1;
626
627 unsigned maxsize = MINMAXTPDU;
628
629 while ( pp < ud - 2 ) {
630 unsigned plen = pp[1];
631
632 if ( pp + plen > ud - 2 ) {
633 MSG_Tsap_RejectUnspecified_LOG ("Bad parameter length field");
634 ProtocolError (qb, pp - dp + 2, Reject_NotSpecified);
635 return;
636 }
637
638 switch ( pp[0] ) {
639 case PARAM_calling_tsel: // Calling TSEL
640 if ( plen <= TSSIZE ) {
641 memcpy (connect.calling.ta_selector, pp+2, plen);
642 connect.calling.ta_selectlen = plen;
643 }
644 break;
645
646 case PARAM_called_tsel: // Called TSEL
647 if ( plen <= TSSIZE ) {
648 memcpy (connect.called.ta_selector, pp+2, plen);
649 connect.called.ta_selectlen = plen;
650 }
651 break;
652
653 case PARAM_tpdusize: // TPDU size
654 {
655 if ( pp[2] < 7 || 13 < pp[2] ) {
656 MSG_Tsap_RejectBadValue_LOG ("TPDU size");
657
658 // Limit to max valid size
659 maxsize = 1U<<13;
660 } else {
661 maxsize = 1U<<pp[2];
662 }
663 break;
664 }
665
666 case PARAM_prefmaxtpdu: // Preferred MAX TPDU size
667 {
668 unsigned psize = 0;
669 for ( unsigned i = 0; i < plen; i++ ) {
670 psize <<= 8;
671 psize |= pp[2+i];
672 }
673
674 // Parameter value is size /128
675 psize <<= 7;
676
677 if ( psize < MINMAXTPDU || 65530 < psize ) {
678 MSG_Tsap_RejectBadValue_LOG ("Preferred TPDU size");
679 ProtocolError (qb, pp - dp + 2 + plen,
680 Reject_InvalidParameterValue);
681 return;
682 }
683
684 maxsize = psize;
685 useprefsize = true;
686 break;
687 }
688
689 case PARAM_version: // Version number
690 if ( pp[2] != 1 ) {
691 MSG_Tsap_RejectBadValue_LOG ("Version number");
692 ProtocolError (qb, pp - dp + 2 + plen,
693 Reject_InvalidParameterValue);
694 return;
695 }
696 break;
697
698 case PARAM_additional: // Additional option selection
699 // No action at present
700 break;
701
702 case PARAM_altclasses: // Alternative protocol classes
703 {
704 for ( unsigned i = 0; i < plen; i++ )
705 classes |= (1U<<(pp[i+2]>>4));
706
707 break;
708 }
709
710 case PARAM_protection: // Protection parameters
711 case PARAM_acktime: // Acknowledgement time
712 case PARAM_throughput: // Throughput
713 case PARAM_residerr: // Residual error rate
714 case PARAM_priority: // Priority
715 case PARAM_transitdelay: // Transit delay
716 case PARAM_reasstime: // Reassignment time
717 case PARAM_inacttime: // Inactivity timer
718 default:
719 // Known parameters which are ignored
720 LOG_DEBUG (("Ignore parameter type 0x%2.2X", pp[0]));
721 break;
722 }
723
724 pp += plen + 2;
725 }
726
727 // Set the size to be used to the smaller of the local limit and
728 // the proposed size.
729 if ( maxsize < maxtpdu )
730 maxtpdu = maxsize;
731
732 // Set the state so that DRs will be sent even if generated locally
733 state = WFTRESP;
734
735 // Reject CR No suitable classes
736 classes &= (TP_CLASS_2|TP_CLASS_0);
737
738 if ( classes == 0 ) {
739 InternalError (DR_negotiation, "No suitable classes");
740 return;
741 }
742
743 if ( classes & TP_CLASS_2 )
744 classes = TP_CLASS_2;
745 else
746 classes = TP_CLASS_0;
747
749 }
750
751 //-------------
753 ConnectIndication conind;
754
755 conind.newprovider = provider;
756 conind.calling = connect.calling;
757 conind.called = connect.called;
758 conind.expedited = false;
759 conind.tsdusize = maxtpdu - ((classes & TP_CLASS_0) ? 3 : 5);
760
761 // No user data at the moment
762 conind.cc = 0;
763 conind.data = 0;
764
765 provider->GetUser()->Deliver (&conind);
766 }
767
768 //-------------
769 void Layer::getCC (struct qbuf *qb)
770 {
771 switch ( state ) {
772 default:
773 ProtocolError (qb, 2, Reject_NotSpecified);
774 return;
775
776 case CLOSING:
777 LOG_DEBUG (("CC received in state closing"));
778 return;
779
780 case CLOSED:
781 SendUserDR (DR_protocol, "CC received when closed");
782 return;
783
784 case WFCC:
785 case WBCL:
786 // Handled later
787 break;
788 }
789
790 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
791
792 if ( dp[0] < 6 ) {
793 MSG_Tsap_RejectUnspecified_LOG ("Bad length field in CC");
794 ProtocolError (qb, 1, Reject_NotSpecified);
795 return;
796 }
797
798 if ( !DstRefOK (qb) ) return;
799
800 classes = (1U<<(dp[6]>>4));
801
802 unsigned options = dp[6] & 0xF;
803
804 if ( options & 0xC ) {
805 MSG_Tsap_RejectBadValue_LOG ("options");
806 ProtocolError (qb, 7, Reject_InvalidParameterValue);
807 return;
808 }
809
810 const u_char *pp = dp + 7;
811 const u_char *ud = dp + dp[0] + 1;
812
813 unsigned maxsize = MINMAXTPDU; // Default if no size parameters
814
815 while ( pp < ud - 2 ) {
816 unsigned plen = pp[1];
817
818 if ( pp + plen > ud - 2 ) {
819 MSG_Tsap_RejectUnspecified_LOG ("Bad parameter length field");
820 ProtocolError (qb, pp - dp + 2, Reject_NotSpecified);
821 return;
822 }
823
824 switch ( pp[0] ) {
825 case PARAM_respond_tsel: // Responsing TSEL
826 if ( plen <= TSSIZE ) {
827 memcpy (connect.called.ta_selector, pp+2, plen);
828 }
829 break;
830
831 case PARAM_tpdusize: // TPDU size
832 {
833 if ( pp[2] < 7 || 13 < pp[2] ) {
834 MSG_Tsap_RejectBadValue_LOG ("TPDU size");
835 ProtocolError (qb, pp - dp + 2 + plen,
836 Reject_InvalidParameterValue);
837 return;
838 }
839
840 unsigned psize = 1U<<pp[2];
841 if ( psize > maxsize )
842 maxsize = psize;
843
844 break;
845 }
846
847 case PARAM_prefmaxtpdu: // Preferred MAX TPDU size
848 {
849 unsigned psize = 0;
850 for ( unsigned i = 0; i < plen; i++ ) {
851 psize <<= 8;
852 psize |= pp[2+i];
853 }
854
855 // Parameter value is size /128
856 psize <<= 7;
857
858 if ( psize < MINMAXTPDU || 65530 < psize ) {
859 MSG_Tsap_RejectBadValue_LOG ("Preferred TPDU size");
860 ProtocolError (qb, pp - dp + 2 + plen,
861 Reject_InvalidParameterValue);
862 return;
863 }
864
865 if ( psize > maxsize )
866 maxsize = psize;
867 break;
868 }
869
870 case PARAM_additional: // Additional option selection
871 // No action at present
872 break;
873
874 case PARAM_calling_tsel: // Calling TSel
875 case PARAM_protection: // Protection parameters
876 case PARAM_acktime: // Acknowledgement time
877 case PARAM_throughput: // Throughput
878 case PARAM_residerr: // Residual error rate
879 case PARAM_priority: // Priority
880 case PARAM_transitdelay: // Transit delay
881 case PARAM_reasstime: // Reassignment time
882 case PARAM_inacttime: // Inactivity timer
883 // Known parameters which are ignored
884 LOG_DEBUG (("Ignore parameter type 0x%2.2X", pp[0]));
885 break;
886
887 default:
888 MSG_Tsap_RejectBadParam_LOG (pp[0]);
889 ProtocolError (qb, pp - dp + 1, Reject_InvalidParameterCode);
890 return;
891 }
892
893 pp += plen + 2;
894 }
895
896 maxtpdu = maxsize;
897
898 if ( state == WBCL || provider->GetUser() == 0 ) {
899 if ( classes & TP_CLASS_0 ) {
900 CloseNetwork();
901
902 } else {
903 makeDR (DR_nosession, 0, 0);
904 state = CLOSING;
905 }
906 return;
907 }
908
909 bool CCOK = true;
910
911 if ( (options & 1) == 0 && (classes & TP_CLASS_0) == 0 )
912 CCOK = false;
913
914 if ( CCOK ) {
915 ConnectConfirm conconf;
916
917 conconf.responding = connect.called;
918 conconf.expedited = connect.expedited;
919
920 conconf.tsdusize = maxtpdu - ((classes & TP_CLASS_0) ? 3 : 5);
921
922 // Check for user data
923 if ( static_cast<unsigned>(dp[0] + 1) < qb->qb_len ) {
924
925 conconf.cc = qb->qb_len - dp[0] - 1;
926
927 char *userdata = static_cast<char *>(malloc (conconf.cc));
928 if ( userdata != 0 )
929 memcpy (userdata, dp + dp[0] + 1, conconf.cc );
930 else
931 conconf.cc = 0;
932
933 conconf.data = userdata;
934
935 } else {
936 conconf.cc = 0;
937 conconf.data = 0;
938 }
939
940 state = OPEN;
941
942 TSnotify (provider->GetUser()->Deliver(&conconf));
943
944 } else {
945 if ( classes & TP_CLASS_0 ) {
946 CloseNetwork();
947
948 } else {
949 makeDR (DR_negotiation, 0, 0);
950 state = CLOSING;
951 }
952
953 DisconnectIndication disind;
954
955 MSG_Tsap_Negotiation_SET (&disind.msg);
956 TDISind (disind);
957 }
958 }
959
960 //-------------
961 void Layer::getDR (struct qbuf *qb)
962 {
963 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
964
965 if ( dp[0] < 6 ) {
966 MSG_Tsap_RejectUnspecified_LOG ("Bad length field in DR");
967 ProtocolError (qb, 1, Reject_NotSpecified);
968 return;
969 }
970
971 if ( !DstRefOK (qb) ) return;
972
973 uint16_t sourceref = (dp[4]<<8) | dp[5];
974
975 bool sendTDISind = true;
976
977 LOG_DEBUG (("getDR (reason=%d)", dp[6]));
978
979 switch ( state ) {
980 case CLOSING:
981 CloseNetwork ();
982 return;
983
984 case OPEN:
985 // Note: should fault DR in Class 0, but RFC 1006
986 // can send it, so allow, but no DC
987 if ( (classes & TP_CLASS_0) == 0 ) {
988 makeDC();
989 }
990 break;
991
992 case WFNC: // (should not occur!)
993 case WFCR:
994 case WFCC:
995 case WFTRESP:
996 break;
997
998 case WBCL:
999 sendTDISind = false;
1000 break;
1001
1002 case CLOSED:
1003 if ( (classes & TP_CLASS_0) == 0 && sourceref != 0 ) {
1004 dstref = sourceref;
1005 makeDC();
1006 }
1007 break;
1008 }
1009
1010 state = CLOSED;
1011 CloseNetwork();
1012
1013 if ( sendTDISind ) {
1014 // ignore additional information and user data
1015 SendUserDR (static_cast<enum DRreason>(dp[6]), 0);
1016 }
1017 }
1018
1019 //-------------
1020 void Layer::getDC (struct qbuf *qb)
1021 {
1022 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
1023
1024 if ( dp[0] < 6 ) {
1025 MSG_Tsap_RejectUnspecified_LOG ("Bad length field");
1026 ProtocolError (qb, 1, Reject_NotSpecified);
1027 return;
1028 }
1029
1030 if ( !DstRefOK (qb) ) return;
1031
1032 if ( state == CLOSED || state == CLOSING ) {
1033 CloseNetwork();
1034 } else {
1035 ProtocolError (qb, 1, Reject_NotSpecified);
1036 return;
1037 }
1038 }
1039
1040 //-------------
1041 void Layer::getDT (struct qbuf *qb)
1042 {
1043 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
1044
1045 unsigned poffset;
1046
1047 DataIndication dataind;
1048
1049 dataind.expedited = false;
1050
1051 if ( classes & TP_CLASS_0 ) {
1052 LOG_DEBUG (("getDT (0) (%d %2.2x) %ld",
1053 dp[0], dp[2] & 0xFF, (long)qb->qb_len - 3));
1054
1055 if ( dp[0] < 2 ) {
1056 MSG_Tsap_RejectUnspecified_LOG ("Bad length field");
1057 ProtocolError (qb, 1, Reject_NotSpecified);
1058 qb_free (qb);
1059 return;
1060 }
1061
1062 dataind.eot = (dp[2] & 0x80) != 0;
1063
1064 poffset = 3;
1065
1066 } else {
1067 LOG_DEBUG (("getDT (2) (%d %2.2x) %ld",
1068 dp[0], dp[4] & 0xFF, (long)qb->qb_len - 5));
1069
1070 if ( dp[0] < 4 ) {
1071 MSG_Tsap_RejectUnspecified_LOG ("Bad length field");
1072 ProtocolError (qb, 1, Reject_NotSpecified);
1073 qb_free (qb);
1074 return;
1075 }
1076
1077 if ( !DstRefOK (qb) ) return;
1078
1079 dataind.eot = (dp[4] & 0x80) != 0;
1080
1081 poffset = 5;
1082 }
1083
1084 qb->qb_data += poffset;
1085 qb->qb_len -= poffset;
1086
1087 dataind.data = qb;
1088
1089 if ( provider->GetUser() != 0 ) {
1090 TSnotify (provider->GetUser()->Deliver (&dataind));
1091
1092 } else {
1093 qb_free (qb);
1094 InternalError (DR_nosession, "Missing user for DT");
1095 }
1096 }
1097
1098 //-------------
1099 void Layer::getED (struct qbuf *qb)
1100 {
1101 // ED not supported at the moment
1102 ProtocolError (qb, 1, Reject_NotSpecified);
1103
1104 // This routine responsible for qbuf
1105 qb_free (qb);
1106 }
1107
1108 //-------------
1109 void Layer::getER (struct qbuf *qb)
1110 {
1111 const u_char *dp = reinterpret_cast<const u_char *>(qb->qb_data);
1112
1113 if ( dp[0] > 3 )
1114 MSG_Tsap_RejectReceived_LOG (dp[4]);
1115
1116 switch ( state ) {
1117 case CLOSED:
1118 case WFNC:
1119 return;
1120
1121 case WBCL:
1122 CloseNetwork ();
1123 return;
1124
1125 case WFCC:
1126 SendUserDR (DR_negotiation, "ER while in WFCC");
1127 CloseNetwork ();
1128 return;
1129
1130 default:
1131 break;
1132 }
1133
1134 SendUserDR (DR_protocol, "ER when open");
1135 CloseNetwork ();
1136 }
1137
1138 //--------------------------------------------------------------------
1139 // TPDU creation
1140
1141 //-------------
1142 void Layer::makeCR ()
1143 {
1144 u_char fixed[128]; // Total maximum length allowed
1145 u_char *dp = fixed + 1;
1146
1147 *dp++ = PDU_CR; // CR+CDT (No initial credit as no explicit control flow)
1148 *dp++ = 0; // DST-REF always zero
1149 *dp++ = 0;
1150
1151 *dp++ = srcref>>8; // SRC-REF
1152 *dp++ = srcref;
1153
1154 // Class Option
1155 if ( classes & TP_CLASS_2 ) {
1156 *dp++ = (2<<4) | 1; // Class 2, Normal formats, no explicit flow
1157 } else {
1158 *dp++ = 0;
1159 }
1160
1161 // Set TPDU size
1162 unsigned logi;
1163 for ( logi = 7; logi < 13; logi++ )
1164 if ( (1U<<logi) >= maxtpdu )
1165 break;
1166
1167 *dp++ = PARAM_tpdusize;
1168 *dp++ = 1;
1169 *dp++ = logi;
1170
1171 // Note: could set Preferred Max TPDU size, but this parameter is
1172 // not in early X.224, and is not supported in the older ISODE TS
1173
1174 // Set version number (unless using Class 0)
1175 if ( classes & TP_CLASS_2 ) {
1176 *dp++ = PARAM_version;
1177 *dp++ = 1;
1178 *dp++ = 1;
1179 }
1180
1181 // Set additional options
1182 if ( connect.expedited ) {
1183 *dp++ = PARAM_additional;
1184 *dp++ = 1;
1185 *dp++ = 1;
1186 }
1187
1188 // Set alternative protocol classes
1189 if ((classes & TP_CLASS_2) && (classes & TP_CLASS_0)) {
1190 *dp++ = PARAM_altclasses;
1191 *dp++ = 1;
1192 *dp++ = 0;
1193 }
1194
1195 // Called selector
1196 if ( connect.called.ta_selectlen > 0 &&
1197 connect.called.ta_selectlen + (dp-fixed) < (int)sizeof fixed - 2){
1198 *dp++ = PARAM_called_tsel;
1199 *dp++ = connect.called.ta_selectlen;
1200 memcpy (dp, connect.called.ta_selector, connect.called.ta_selectlen);
1201 dp += connect.called.ta_selectlen;
1202 }
1203
1204 // Calling selector
1205 if ( connect.calling.ta_selectlen > 0 &&
1206 connect.calling.ta_selectlen + (dp-fixed) < (int)sizeof fixed - 2){
1207 *dp++ = PARAM_calling_tsel;
1208 *dp++ = connect.calling.ta_selectlen;
1209 memcpy (dp, connect.calling.ta_selector, connect.calling.ta_selectlen);
1210 dp += connect.calling.ta_selectlen;
1211 }
1212
1213 // Set LI
1214 unsigned len = dp - fixed;
1215 fixed[0] = len - 1;
1216
1217 TPbuffer *bufp = GetBuffer();
1218 if ( bufp == 0 ) return;
1219
1220 bufp = TPbuffer::Add (bufp, fixed, len);
1221 if ( bufp == 0 ) return;
1222
1223 if ( connect.cc != 0 && (len + connect.cc) <= 128 )
1224 bufp = TPbuffer::Add (bufp,
1225 reinterpret_cast<const u_char *>(connect.data),
1226 connect.cc);
1227
1228 WritePDU (bufp);
1229 }
1230
1231 //-------------
1232 void Layer::makeCC ()
1233 {
1234 u_char fixed[128]; // Total maximum length allowed
1235 u_char *dp = fixed + 1;
1236
1237 *dp++ = PDU_CC; // CC+CDT (No initial credit as no explicit flow control)
1238
1239 *dp++ = dstref>>8; // DST-REF
1240 *dp++ = dstref;
1241
1242 *dp++ = srcref>>8; // SRC-REF
1243 *dp++ = srcref;
1244
1245 // Class Option
1246 if ( classes & TP_CLASS_2 ) {
1247 *dp++ = (2<<4) | 1; // Class 2, Normal formats, no explicit flow
1248 } else {
1249 *dp++ = 0;
1250 }
1251
1252 // Set TPDU size
1253 if ( useprefsize ) {
1254 // Parameter value is number of 128 byte chunks
1255 // Cannot be more than 2 bytes in size
1256 unsigned pval = maxtpdu >> 7;
1257
1258 *dp++ = PARAM_prefmaxtpdu;
1259 if ( pval & 0xFF00 ) {
1260 *dp++ = 2;
1261 *dp++ = pval>>8;
1262 *dp++ = pval;
1263 } else {
1264 *dp++ = 1;
1265 *dp++ = pval;
1266 }
1267
1268 } else {
1269 unsigned logi;
1270 for ( logi = 7; logi < 13; logi++ )
1271 if ( (1U<<logi) >= maxtpdu )
1272 break;
1273
1274 *dp++ = PARAM_tpdusize;
1275 *dp++ = 1;
1276 *dp++ = logi;
1277 }
1278
1279 // Set additional options
1280 if ( connect.expedited ) {
1281 *dp++ = PARAM_additional;
1282 *dp++ = 1;
1283 *dp++ = 1;
1284 }
1285
1286 // Should not be alternative protocol classes
1287
1288 // Called selector
1289 if ( connect.called.ta_selectlen > 0 &&
1290 connect.called.ta_selectlen + (dp-fixed) < (int)sizeof fixed - 2){
1291 *dp++ = PARAM_called_tsel;
1292 *dp++ = connect.called.ta_selectlen;
1293 memcpy (dp, connect.called.ta_selector, connect.called.ta_selectlen);
1294 dp += connect.called.ta_selectlen;
1295 }
1296
1297 // Set LI
1298 unsigned len = dp - fixed;
1299 fixed[0] = len - 1;
1300
1301 TPbuffer *bufp = GetBuffer();
1302 if ( bufp == 0 ) return;
1303
1304 bufp = TPbuffer::Add (bufp, fixed, len);
1305 if ( bufp == 0 ) return;
1306
1307 if ( connect.cc != 0 && (len + connect.cc) <= 128 )
1308 bufp = TPbuffer::Add (bufp,
1309 reinterpret_cast<const u_char *>(connect.data),
1310 connect.cc);
1311
1312 WritePDU (bufp);
1313 }
1314
1315 //-------------
1316 void Layer::makeDR (enum DRreason reason,
1317 const char *data,
1318 unsigned cc)
1319 {
1320 u_char fixed[128];
1321 u_char *dp = fixed + 1;
1322
1323 *dp++ = PDU_DR; // DR
1324
1325 *dp++ = dstref>>8; // DST-REF
1326 *dp++ = dstref;
1327
1328 *dp++ = srcref>>8; // SRC-REF
1329 *dp++ = srcref;
1330
1331 if ( state != CLOSED && (classes & TP_CLASS_2) == 0 ) {
1332 // If up and running and class 0, make valid reason code
1333 switch ( reason ) {
1334 case DR_notspecified:
1335 case DR_congestion:
1336 case DR_nosession:
1337 case DR_address:
1338 break;
1339
1340 case DR_remcongested:
1341 reason = DR_congestion;
1342 break;
1343
1344 case DR_normal:
1345 case DR_negotiation:
1346 case DR_duplicate:
1347 case DR_mismatched:
1348 case DR_protocol:
1349 case DR_reference:
1350 case DR_network:
1351 case DR_invalidlen:
1352 case DR_waitclose:
1353 reason = DR_notspecified;
1354 break;
1355 }
1356 }
1357
1358 *dp++ = reason; // Reason
1359
1360 fixed[0] = dp - fixed - 1;
1361
1362 if ( 0 < cc && cc <= 64 ) {
1363 memcpy (dp, data, cc);
1364 dp += cc;
1365 }
1366
1367 TPbuffer *bufp = GetBuffer();
1368 if ( bufp == 0 ) return;
1369
1370 WritePDU (TPbuffer::Add (bufp, fixed, dp - fixed));
1371 }
1372
1373 //-------------
1374 void Layer::makeDC ()
1375 {
1376 u_char fixed[16];
1377 u_char *dp = fixed + 1;
1378
1379 *dp++ = PDU_DC; // DC
1380
1381 *dp++ = dstref>>8; // DST-REF
1382 *dp++ = dstref;
1383
1384 *dp++ = srcref>>8; // SRC-REF
1385 *dp++ = srcref;
1386
1387 fixed[0] = dp - fixed - 1;
1388
1389 TPbuffer *bufp = GetBuffer();
1390 if ( bufp == 0 ) return;
1391
1392 WritePDU (TPbuffer::Add (bufp, fixed, dp - fixed));
1393 }
1394
1395 //-------------
1396 void Layer::makeDT (const struct udvec *uv, bool eot)
1397 {
1398 if ( uv == 0 || uv->uv_base == 0 ) return;
1399
1400 u_char fixed[16];
1401 u_char *dp = fixed + 1;
1402
1403 *dp++ = PDU_DT; // DT (no ack request)
1404
1405 // No DST-REF in class 0
1406 if ( classes & TP_CLASS_2 ) {
1407 *dp++ = dstref>>8; // DST-REF
1408 *dp++ = dstref;
1409 }
1410
1411 // TPDU-NR and EOT set later
1412 unsigned eotoff = dp - fixed;
1413
1414 *dp++ = 0;
1415
1416 fixed[0] = dp - fixed - 1;
1417
1418 TPbuffer *bufp = GetBuffer();
1419 if ( bufp == 0 ) return;
1420 bufp = TPbuffer::Add (bufp, fixed, dp - fixed);
1421 if ( bufp == 0 ) return;
1422
1423 for ( ; uv->uv_base ; uv++ ) {
1424 const u_char *datap = reinterpret_cast<const u_char *>(uv->uv_base);
1425 unsigned dlen = uv->uv_len;
1426
1427 while ( dlen > 0 ) {
1428 unsigned dcopy = dlen;
1429
1430 if ( bufp->dlen + dcopy > maxtpdu )
1431 dcopy = maxtpdu - bufp->dlen;
1432
1433 bufp = TPbuffer::Add (bufp, datap, dcopy);
1434 if ( bufp == 0 ) {
1435 InternalError (DR_congestion, "out of memory");
1436 return;
1437 }
1438
1439 datap += dcopy;
1440 dlen -= dcopy;
1441
1442 if ( dlen > 0 ) {
1443 // Must have filled the TPDU, so send it and get another
1444 // as there is more data to send
1445
1446 // If we were to set the TPDU-NR, it should be set here
1447 // EOT is only ever set on the last one of the group
1448 WritePDU (bufp);
1449
1450 bufp = GetBuffer();
1451 if ( bufp == 0 ) return;
1452 bufp = TPbuffer::Add (bufp, fixed, dp - fixed);
1453 if ( bufp == 0 ) return;
1454 }
1455 }
1456 }
1457
1458 if ( eot )
1459 bufp->data[bufp->doff+eotoff] |= EOT_FLAG;
1460
1461 WritePDU (bufp);
1462 }
1463
1464 //-------------
1465 void Layer::makeED (const u_char *data, unsigned len)
1466 {
1467 u_char fixed[32];
1468 u_char *dp = fixed + 1;
1469
1470 *dp++ = PDU_ED; // ED
1471
1472 *dp++ = dstref>>8; // DST-REF
1473 *dp++ = dstref;
1474
1475 // Set ED-TPDU-NR + EOT
1476 *dp++ = EOT_FLAG;
1477
1478 fixed[0] = dp - fixed - 1;
1479
1480 TPbuffer *bufp = GetBuffer();
1481 if ( bufp == 0 ) return;
1482
1483 bufp = TPbuffer::Add (bufp, fixed, dp - fixed);
1484
1485 WritePDU (TPbuffer::Add (bufp,
1486 static_cast<const u_char *>(data),
1487 len));
1488 }
1489
1490 //-------------
1491 void Layer::makeER (enum RejectCause cause,
1492 const u_char *tpdu, unsigned len)
1493 {
1494 u_char fixed[256];
1495 u_char *dp = fixed + 1;
1496
1497 *dp++ = PDU_ER; // ER
1498
1499 *dp++ = dstref>>8; // DST-REF
1500 *dp++ = dstref;
1501
1502 *dp++ = cause; // REJECT CAUSE
1503
1504 if ( len > 0 ) {
1505 if ( len > 250 ) len = 250;
1506 *dp++ = PARAM_invalid_tpdu;
1507 *dp++ = len;
1508 memcpy (dp, tpdu, len);
1509 dp += len;
1510 }
1511
1512 fixed[0] = dp - fixed - 1;
1513
1514 TPbuffer *bufp = GetBuffer();
1515 if ( bufp == 0 ) return;
1516
1517 WritePDU (TPbuffer::Add (bufp, fixed, dp - fixed));
1518 }
1519
1520 //-----------------------------------------------------------------------
1521
1522 class NotifyEvent : public Event::AsyncEvent {
1523 User_ptr_t notifier;
1524
1525 public:
1526 NotifyEvent (User_ptr_t np) : notifier(np) {}
1527
1528 virtual void Deliver () {
1529 notifier->Notify();
1530 delete this;
1531 }
1532 };
1533
1534 void TSnotify (User_ptr_t notifier)
1535 {
1536 if ( !notifier ||
1537 !notifier.get() ||
1538 !notifier.get()->ShouldNotify()) return;
1539
1540 NotifyEvent *nevent = new NotifyEvent (notifier);
1541
1542 Event::Manager::GetManager()->Queue (nevent);
1543 }
1544}
EVENTSVC_DLL void TSnotify(const User_ptr_t notifier)
Send a notification to the transport service used via the Event Manager.
Definition TPlayer.C:1534
#define TP_CLASS_0
Provides a Class 0 and Class 2 interface layer.
Definition TPlayer.h:31
virtual void ConnectRequest(struct NSAPaddr &calling, struct NSAPaddr &called)=0
Connect networks.
virtual void DisconnectRequest(bool force=true)=0
Disconnect Network connection.
EVENTSVC_DLL void Deliver(ConnectRequest *req)
TCONreq.
Definition TPlayer.C:83
EVENTSVC_DLL void NetworkRead(struct qbuf *qb)
Handle data from network.
Definition TPlayer.C:244
EVENTSVC_DLL void GetSaveInfo(char *buffer, size_t buflen)
Get save information from layer.
Definition TPlayer.C:524
@ WFCR
Wait for network Connect.
Definition TPlayer.h:158
@ WFTRESP
Release in progress.
Definition TPlayer.h:163
@ WFNC
Closed.
Definition TPlayer.h:157
@ WBCL
Wait for CC-TPDU.
Definition TPlayer.h:160
@ CLOSING
Transport connection is open.
Definition TPlayer.h:162
@ OPEN
Wait before releasing.
Definition TPlayer.h:161
@ WFCC
Wait for CR-TPDU.
Definition TPlayer.h:159
EVENTSVC_DLL bool NetworkStatus(MSGstruct *msp)
Network status indication.
Definition TPlayer.C:306
EVENTSVC_DLL bool SetSaveInfo(const char *buffer)
Set state from save info.
Definition TPlayer.C:545
EVENTSVC_DLL void SendConnectIndication()
Send TS user a connect indication.
Definition TPlayer.C:752
static TPbuffer * Add(TPbuffer *bufp, const u_char *bytes, unsigned len)
Add bytes to buffer.
Definition TPlayer.h:77

All rights reserved © 2002 - 2024 Isode Ltd.