Coverage Report

Created: 2026-08-31 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libiec61850/src/mms/iso_presentation/iso_presentation.c
Line
Count
Source
1
/*
2
 *  iso_presentation.c
3
 *
4
 *  Copyright 2013-2026 Michael Zillgith
5
 *
6
 *  This file is part of libIEC61850.
7
 *
8
 *  libIEC61850 is free software: you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation, either version 3 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  libIEC61850 is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with libIEC61850.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 *  See COPYING file for the complete license text.
22
 */
23
24
#include "libiec61850_platform_includes.h"
25
26
#include "iso_presentation.h"
27
#include "stack_config.h"
28
#include "ber_encoder.h"
29
#include "ber_decode.h"
30
#include "buffer_chain.h"
31
32
#if ((DEBUG_ISO_SERVER == 1) || (DEBUG_ISO_CLIENT == 1))
33
#define DEBUG_PRES 1
34
#else
35
512k
#define DEBUG_PRES 0
36
#endif
37
38
static uint8_t calledPresentationSelector[] = { 0x00, 0x00, 0x00, 0x01 };
39
40
static uint8_t asn_id_as_acse[] = { 0x52, 0x01, 0x00, 0x01 };
41
42
static uint8_t asn_id_mms[] = { 0x28, 0xca, 0x22, 0x02, 0x01 };
43
44
static uint8_t ber_id[] = { 0x51, 0x01 };
45
46
static int
47
encodeAcceptBer(uint8_t* buffer, int bufPos)
48
42
{
49
42
    bufPos = BerEncoder_encodeTL(0x30, 7, buffer, bufPos);
50
42
    bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos);
51
42
    buffer[bufPos++] = 0;
52
42
    bufPos = BerEncoder_encodeTL(0x81, 2, buffer, bufPos);
53
42
    buffer[bufPos++] = 0x51;
54
42
    buffer[bufPos++] = 0x01;
55
56
42
    return bufPos;
57
42
}
58
59
static int
60
encodeUserData(uint8_t* buffer, int bufPos,
61
        BufferChain payload, bool encode, uint8_t contextId)
62
84
{
63
84
    int payloadLength = payload->length;
64
65
84
    int encodedDataSetLength = 3; /* presentation-selector */
66
67
    /* presentation-data */
68
84
    encodedDataSetLength += payloadLength + 1;
69
84
    encodedDataSetLength += BerEncoder_determineLengthSize(payloadLength);
70
71
84
    int fullyEncodedDataLength = encodedDataSetLength;
72
73
84
    fullyEncodedDataLength += BerEncoder_determineLengthSize(encodedDataSetLength) + 1;
74
75
84
    if (encode)
76
42
    {
77
        /* fully-encoded-data */
78
42
        bufPos = BerEncoder_encodeTL(0x61, fullyEncodedDataLength, buffer, bufPos);
79
42
        bufPos = BerEncoder_encodeTL(0x30, encodedDataSetLength, buffer, bufPos);
80
81
        /* presentation-selector acse */
82
42
        bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos);
83
42
        buffer[bufPos++] = contextId;
84
85
        /* presentation-data (= acse payload) */
86
42
        bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos);
87
88
42
        return bufPos;
89
42
    }
90
42
    else
91
42
    {
92
42
        int encodedUserDataLength = fullyEncodedDataLength + 1;
93
42
        encodedUserDataLength += BerEncoder_determineLengthSize(fullyEncodedDataLength);
94
95
42
        return encodedUserDataLength;
96
42
    }
97
84
}
98
99
static void
100
createConnectPdu(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload)
101
21
{
102
21
    int contentLength = 0;
103
21
    int i;
104
105
    /* mode-selector */
106
21
    contentLength += 5;
107
108
21
    int normalModeLength = 0;
109
110
    /* called- and calling-presentation-selector */
111
21
    normalModeLength += 12;
112
113
21
    int pclLength = 27; /* 35; */
114
21
    pclLength += self->callingPresentationSelector.size;
115
21
    pclLength += self->calledPresentationSelector.size;
116
117
21
    normalModeLength += pclLength;
118
119
21
    normalModeLength += encodeUserData(NULL, 0, payload, false, self->acseContextId);
120
121
21
    normalModeLength += 2;
122
123
21
    contentLength += normalModeLength;
124
125
21
    contentLength += 1 + BerEncoder_determineLengthSize(normalModeLength);
126
127
21
    uint8_t* buffer = writeBuffer->buffer;
128
21
    int bufPos = 0;
129
130
21
    bufPos = BerEncoder_encodeTL(0x31, contentLength, buffer, bufPos);
131
132
    /* mode-selector */
133
21
    bufPos = BerEncoder_encodeTL(0xa0, 3, buffer, bufPos);
134
21
    bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos);
135
21
    buffer[bufPos++] = 1; /* 1 = normal-mode */
136
137
    /* normal-mode-parameters */
138
21
    bufPos = BerEncoder_encodeTL(0xa2, normalModeLength, buffer, bufPos);
139
140
    /* calling-presentation-selector */
141
21
    bufPos = BerEncoder_encodeTL(0x81, self->callingPresentationSelector.size, buffer, bufPos);
142
105
    for (i = 0; i < self->callingPresentationSelector.size; i++)
143
84
        buffer[bufPos++] = self->callingPresentationSelector.value[i];
144
145
    /* called-presentation-selector */
146
21
    bufPos = BerEncoder_encodeTL(0x82, self->calledPresentationSelector.size, buffer, bufPos);
147
105
    for (i = 0; i < self->calledPresentationSelector.size; i++)
148
84
        buffer[bufPos++] = self->calledPresentationSelector.value[i];
149
150
    /* presentation-context-id list */
151
21
    bufPos = BerEncoder_encodeTL(0xa4, 35, buffer, bufPos);
152
153
    /* acse context list item */
154
21
    bufPos = BerEncoder_encodeTL(0x30, 15, buffer, bufPos);
155
156
21
    bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos);
157
21
    buffer[bufPos++] = 1;
158
159
21
    bufPos = BerEncoder_encodeTL(0x06, 4, buffer, bufPos);
160
21
    memcpy(buffer + bufPos, asn_id_as_acse, 4);
161
21
    bufPos += 4;
162
163
21
    bufPos = BerEncoder_encodeTL(0x30, 4, buffer, bufPos);
164
21
    bufPos = BerEncoder_encodeTL(0x06, 2, buffer, bufPos);
165
21
    memcpy(buffer + bufPos, ber_id, 2);
166
21
    bufPos += 2;
167
168
    /* mms context list item */
169
21
    bufPos = BerEncoder_encodeTL(0x30, 16, buffer, bufPos);
170
171
21
    bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos);
172
21
    buffer[bufPos++] = 3;
173
174
21
    bufPos = BerEncoder_encodeTL(0x06, 5, buffer, bufPos);
175
21
    memcpy(buffer + bufPos, asn_id_mms, 5);
176
21
    bufPos += 5;
177
178
21
    bufPos = BerEncoder_encodeTL(0x30, 4, buffer, bufPos);
179
21
    bufPos = BerEncoder_encodeTL(0x06, 2, buffer, bufPos);
180
21
    memcpy(buffer + bufPos, ber_id, 2);
181
21
    bufPos += 2;
182
183
    /* encode user data */
184
21
    bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId);
185
186
21
    writeBuffer->partLength = bufPos;
187
21
    writeBuffer->length = bufPos + payload->length;
188
21
    writeBuffer->nextPart = payload;
189
21
}
190
191
static int
192
parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPos)
193
1.63k
{
194
1.63k
    int presentationSelector = -1;
195
1.63k
    bool userDataPresent = false;
196
197
1.63k
    int endPos = bufPos + len;
198
199
1.63k
    if (len < 1 || buffer[bufPos++] != 0x30)
200
15
    {
201
15
        if (DEBUG_PRES)
202
0
            printf("PRES: user-data parse error\n");
203
15
        return -1;
204
15
    }
205
206
1.61k
    bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
207
208
1.61k
    if (bufPos < 0)
209
2
    {
210
2
        if (DEBUG_PRES)
211
0
            printf("PRES: wrong parameter length\n");
212
2
        return -1;
213
2
    }
214
215
1.61k
    endPos = bufPos + len;
216
217
60.8k
    while (bufPos < endPos)
218
59.3k
    {
219
59.3k
        uint8_t tag = buffer[bufPos++];
220
59.3k
        int length;
221
222
59.3k
        bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos);
223
224
59.3k
        if (bufPos < 0)
225
24
        {
226
24
            if (DEBUG_PRES)
227
0
                printf("PRES: wrong parameter length\n");
228
24
            return -1;
229
24
        }
230
231
59.2k
        switch (tag)
232
59.2k
        {
233
36.1k
        case 0x02: /* presentation-context-identifier */
234
36.1k
            if (DEBUG_PRES)
235
0
                printf("PRES: presentation-context-identifier\n");
236
36.1k
            {
237
36.1k
                presentationSelector = BerDecoder_decodeUint32(buffer, length, bufPos);
238
36.1k
                self->nextContextId = presentationSelector;
239
36.1k
                bufPos += length;
240
36.1k
            }
241
36.1k
            break;
242
243
5.73k
        case 0x06: /* transfer-syntax-name */
244
5.73k
            bufPos += length;
245
5.73k
            break;
246
247
2.23k
        case 0xa0:
248
2.23k
            if (DEBUG_PRES)
249
0
                printf("PRES: fully-encoded-data\n");
250
251
2.23k
            userDataPresent = true;
252
253
2.23k
            self->nextPayload.buffer = buffer + bufPos;
254
2.23k
            self->nextPayload.size = length;
255
256
2.23k
            bufPos += length;
257
2.23k
            break;
258
259
7.32k
        case 0x00: /* indefinite length end tag -> ignore */
260
7.32k
            break;
261
262
7.79k
        default:
263
7.79k
            if (DEBUG_PRES)
264
0
                printf("PRES: fed: unknown tag %02x\n", tag);
265
266
7.79k
            bufPos += length;
267
7.79k
            break;
268
59.2k
        }
269
59.2k
    }
270
271
1.58k
    if (!userDataPresent)
272
55
    {
273
55
        if (DEBUG_PRES)
274
0
            printf("PRES: user-data not present\n");
275
55
        return -1;
276
55
    }
277
278
1.53k
    return bufPos;
279
1.58k
}
280
281
static int
282
parsePCDLEntry(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos)
283
1.61k
{
284
1.61k
    int endPos = bufPos + totalLength;
285
286
1.61k
    int contextId = -1;
287
1.61k
    bool isAcse = false;
288
1.61k
    bool isMms = false;
289
290
459k
    while (bufPos < endPos)
291
458k
    {
292
458k
        uint8_t tag = buffer[bufPos++];
293
458k
        int len;
294
295
458k
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
296
297
458k
        if (bufPos < 0)
298
30
        {
299
30
            if (DEBUG_PRES)
300
0
                printf("PRES: Invalid PDU\n");
301
30
            return -1;
302
30
        }
303
304
458k
        switch (tag) {
305
28.3k
        case 0x02: /* presentation-context-identifier */
306
28.3k
            contextId = BerDecoder_decodeUint32(buffer, len, bufPos);
307
28.3k
            bufPos += len;
308
28.3k
            break;
309
310
163k
        case 0x06: /* abstract-syntax-name */
311
163k
            if (DEBUG_PRES)
312
0
                printf("PRES: abstract-syntax-name with len %i\n", len);
313
314
163k
            if (len == 5)
315
153k
            {
316
153k
                if (memcmp(buffer + bufPos, asn_id_mms, 5) == 0)
317
136k
                    isMms = true;
318
153k
            }
319
9.56k
            else if (len == 4)
320
1.64k
            {
321
1.64k
                if (memcmp(buffer + bufPos, asn_id_as_acse, 4) == 0)
322
991
                    isAcse = true;
323
1.64k
            }
324
325
163k
            bufPos += len;
326
327
163k
            break;
328
329
1.70k
        case 0x30: /* transfer-syntax-name */
330
1.70k
            if (DEBUG_PRES)
331
0
                printf("PRES: ignore transfer-syntax-name\n");
332
333
1.70k
            bufPos += len;
334
1.70k
            break;
335
336
108k
        case 0x00: /* indefinite length end tag -> ignore */
337
108k
            break;
338
339
156k
        default:
340
156k
            if (DEBUG_PRES)
341
0
                printf("PRES: unknown tag in presentation-context-definition-list-entry\n");
342
156k
            bufPos += len;
343
156k
            break;
344
458k
        }
345
458k
    }
346
347
1.58k
    if (contextId < 0)
348
164
    {
349
164
        if (DEBUG_PRES)
350
0
            printf("PRES: ContextId not defined!\n");
351
164
        return -1;
352
164
    }
353
354
1.42k
    if ((isAcse == false) && (isMms == false))
355
46
    {
356
46
        if (DEBUG_PRES)
357
0
            printf("PRES: not an ACSE or MMS context definition\n");
358
359
46
        return -1;
360
46
    }
361
362
1.37k
    if (isMms)
363
1.13k
    {
364
1.13k
        self->mmsContextId = (uint8_t)contextId;
365
1.13k
        if (DEBUG_PRES)
366
0
            printf("PRES: MMS context id is %i\n", contextId);
367
1.13k
    }
368
247
    else
369
247
    {
370
247
        self->acseContextId = (uint8_t)contextId;
371
247
        if (DEBUG_PRES)
372
0
            printf("PRES: ACSE context id is %i\n", contextId);
373
247
    }
374
375
1.37k
    return bufPos;
376
1.42k
}
377
378
static int
379
parsePresentationContextDefinitionList(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos)
380
1.03k
{
381
1.03k
    int endPos = bufPos + totalLength;
382
383
7.87k
    while (bufPos < endPos)
384
7.09k
    {
385
7.09k
        uint8_t tag = buffer[bufPos++];
386
7.09k
        int len;
387
388
7.09k
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
389
7.09k
        if (bufPos < 0)
390
19
            return -1;
391
392
7.07k
        switch (tag)
393
7.07k
        {
394
1.61k
        case 0x30:
395
1.61k
            if (DEBUG_PRES)
396
0
                printf("PRES: parse pcd entry\n");
397
1.61k
            bufPos = parsePCDLEntry(self, buffer, len, bufPos);
398
1.61k
            if (bufPos < 0)
399
240
                return -1;
400
1.37k
            break;
401
1.37k
        case 0x00: /* indefinite length end tag -> ignore */
402
741
            break;
403
4.72k
        default:
404
4.72k
            if (DEBUG_PRES)
405
0
                printf("PRES: unknown tag in presentation-context-definition-list\n");
406
4.72k
            bufPos += len;
407
4.72k
            break;
408
7.07k
        }
409
7.07k
    }
410
411
776
    return bufPos;
412
1.03k
}
413
414
static int
415
parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos)
416
1.65k
{
417
1.65k
    int endPos = bufPos + totalLength;
418
419
1.65k
    self->calledPresentationSelector.size = 0;
420
1.65k
    self->callingPresentationSelector.size = 0;
421
422
1.65k
    bool hasUserData = false;
423
424
23.9k
    while (bufPos < endPos)
425
22.6k
    {
426
22.6k
        uint8_t tag = buffer[bufPos++];
427
22.6k
        int len;
428
429
22.6k
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
430
431
22.6k
        if (bufPos < 0)
432
24
        {
433
24
            if (DEBUG_PRES)
434
0
                printf("PRES: wrong parameter length\n");
435
24
            return -1;
436
24
        }
437
438
22.6k
        switch (tag)
439
22.6k
        {
440
1.44k
        case 0x81: /* calling-presentation-selector */
441
442
1.44k
            if (len > 16)
443
216
            {
444
216
                if (DEBUG_PRES)
445
0
                    printf("PRES: calling-presentation-sel too large\n");
446
216
            }
447
1.22k
            else
448
1.22k
            {
449
1.22k
                self->callingPresentationSelector.size = len;
450
1.22k
                int i;
451
3.14k
                for (i = 0; i < len; i++)
452
1.91k
                    self->callingPresentationSelector.value[i] = buffer[bufPos + i];
453
1.22k
            }
454
455
1.44k
            bufPos += len;
456
1.44k
            break;
457
458
687
        case 0x82: /* called-presentation-selector */
459
460
687
            if (len > 16)
461
219
            {
462
219
                if (DEBUG_PRES)
463
0
                    printf("PRES: called-presentation-sel too large\n");
464
219
            }
465
468
            else
466
468
            {
467
468
                self->calledPresentationSelector.size = len;
468
468
                int i;
469
1.05k
                for (i = 0; i < len; i++)
470
590
                    self->calledPresentationSelector.value[i] = buffer[bufPos + i];
471
468
            }
472
473
687
            bufPos += len;
474
687
            break;
475
476
215
        case 0x83: /* responding-presentation-selector */
477
478
215
            if (len > 16)
479
0
            {
480
0
                if (DEBUG_PRES)
481
0
                    printf("PRES: responding-presentation-sel too large\n");
482
0
            }
483
484
215
            bufPos += len;
485
215
            break;
486
487
1.03k
        case 0xa4: /* presentation-context-definition list */
488
1.03k
            if (DEBUG_PRES)
489
0
                printf("PRES: pcd list\n");
490
1.03k
            bufPos = parsePresentationContextDefinitionList(self, buffer, len, bufPos);
491
492
1.03k
            if (bufPos < 0)
493
259
                return -1;
494
495
776
            break;
496
497
776
        case 0xa5: /* context-definition-result-list */
498
499
221
            bufPos += len;
500
221
            break;
501
502
1.63k
        case 0x61: /* user data */
503
1.63k
            if (DEBUG_PRES)
504
0
                printf("PRES: user-data\n");
505
506
1.63k
            bufPos = parseFullyEncodedData(self, buffer, len, bufPos);
507
508
1.63k
            if (bufPos < 0)
509
96
                return -1;
510
511
1.53k
            if (self->nextPayload.size > 0)
512
1.09k
                hasUserData = true;
513
514
1.53k
            break;
515
516
5.65k
        case 0x00: /* indefinite length end tag -> ignore */
517
5.65k
            break;
518
519
11.7k
        default:
520
11.7k
            if (DEBUG_PRES)
521
0
                printf("PRES: unknown tag in normal-mode\n");
522
11.7k
            bufPos += len;
523
11.7k
            break;
524
22.6k
        }
525
22.6k
    }
526
527
1.27k
    if (hasUserData == false)
528
253
    {
529
253
        if (DEBUG_PRES)
530
0
            printf("PRES: user-data is missing\n");
531
532
253
        return -1;
533
253
    }
534
535
1.02k
    return bufPos;
536
1.27k
}
537
538
int
539
IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer)
540
1.08k
{
541
1.08k
    uint8_t* buffer = byteBuffer->buffer;
542
1.08k
    int maxBufPos = byteBuffer->size;
543
544
1.08k
    int bufPos = 0;
545
546
1.08k
    if (maxBufPos < 1)
547
0
    {
548
0
        if (DEBUG_PRES)
549
0
            printf("PRES: invalid message!\n");
550
0
        return 0;
551
0
    }
552
553
1.08k
    uint8_t cpTag = buffer[bufPos++];
554
555
1.08k
    if (cpTag != 0x31)
556
14
    {
557
14
        if (DEBUG_PRES)
558
0
            printf("PRES: not a CPA message\n");
559
14
        return 0;
560
14
    }
561
562
1.07k
    int len;
563
564
1.07k
    bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
565
566
1.07k
    if (bufPos < 0)
567
156
    {
568
156
        if (DEBUG_PRES)
569
0
            printf("PRES: Invalid message\n");
570
156
        return 0;
571
156
    }
572
573
228k
    while (bufPos < maxBufPos)
574
228k
    {
575
228k
        uint8_t tag = buffer[bufPos++];
576
577
228k
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
578
579
228k
        if (bufPos < 0)
580
119
        {
581
119
            if (DEBUG_PRES)
582
0
                printf("PRES: wrong parameter length\n");
583
119
            return 0;
584
119
        }
585
586
228k
        switch (tag) {
587
7.78k
        case 0xa0: /* mode-selector */
588
7.78k
            bufPos += len; /* ignore content since only normal mode is allowed */
589
7.78k
            break;
590
1.63k
        case 0xa2: /* normal-mode-parameters */
591
1.63k
            bufPos = parseNormalModeParameters(self, buffer, len, bufPos);
592
593
1.63k
            if (bufPos < 0)
594
632
            {
595
632
                if (DEBUG_PRES)
596
0
                    printf("PRES: error parsing normal-mode-parameters\n");
597
632
                return 0;
598
632
            }
599
600
999
            break;
601
98.4k
        case 0x00: /* indefinite length end tag -> ignore */
602
98.4k
            break;
603
120k
        default:
604
120k
            if (DEBUG_PRES)
605
0
                printf("PRES: CPA unknown tag %i\n", tag);
606
120k
            bufPos += len;
607
120k
            break;
608
228k
        }
609
228k
    }
610
611
164
    return 1;
612
915
}
613
614
void
615
IsoPresentation_init(IsoPresentation* self)
616
42
{
617
42
    (void)self;
618
42
}
619
620
void
621
IsoPresentation_createUserData(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload)
622
25
{
623
25
    int bufPos = 0;
624
25
    uint8_t* buffer = writeBuffer->buffer;
625
626
25
    int payloadLength = payload->length;
627
628
25
    int userDataLengthFieldSize = BerEncoder_determineLengthSize(payloadLength);
629
630
25
    int pdvListLength = payloadLength + (userDataLengthFieldSize + 4);
631
632
25
    int pdvListLengthFieldSize = BerEncoder_determineLengthSize(pdvListLength);
633
25
    int presentationLength = pdvListLength + (pdvListLengthFieldSize + 1);
634
635
25
    bufPos = BerEncoder_encodeTL(0x61, presentationLength, buffer, bufPos);
636
637
25
    bufPos = BerEncoder_encodeTL(0x30, pdvListLength, buffer, bufPos);
638
639
25
    buffer[bufPos++] = (uint8_t) 0x02;
640
25
    buffer[bufPos++] = (uint8_t) 0x01;
641
25
    buffer[bufPos++] = (uint8_t) self->mmsContextId; /* mms context id */
642
643
25
    bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos);
644
645
25
    writeBuffer->partLength = bufPos;
646
25
    writeBuffer->length = bufPos + payloadLength;
647
25
    writeBuffer->nextPart = payload;
648
25
}
649
650
void
651
IsoPresentation_createUserDataACSE(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload)
652
0
{
653
0
    int bufPos = 0;
654
0
    uint8_t* buffer = writeBuffer->buffer;
655
656
0
    int payloadLength = payload->length;
657
658
0
    int userDataLengthFieldSize = BerEncoder_determineLengthSize(payloadLength);
659
660
0
    int pdvListLength = payloadLength + (userDataLengthFieldSize + 4);
661
662
0
    int pdvListLengthFieldSize = BerEncoder_determineLengthSize(pdvListLength);
663
0
    int presentationLength = pdvListLength + (pdvListLengthFieldSize + 1);
664
665
0
    bufPos = BerEncoder_encodeTL(0x61, presentationLength, buffer, bufPos);
666
667
0
    bufPos = BerEncoder_encodeTL(0x30, pdvListLength, buffer, bufPos);
668
669
0
    buffer[bufPos++] = (uint8_t) 0x02;
670
0
    buffer[bufPos++] = (uint8_t) 0x01;
671
0
    buffer[bufPos++] = (uint8_t) self->acseContextId; /* ACSE context id */
672
673
0
    bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos);
674
675
0
    writeBuffer->partLength = bufPos;
676
0
    writeBuffer->length = bufPos + payloadLength;
677
0
    writeBuffer->nextPart = payload;
678
0
}
679
680
int
681
IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer)
682
25
{
683
25
    uint8_t* buffer = readBuffer->buffer;
684
25
    int maxBufPos = readBuffer->size;
685
25
    bool hasAbstractSyntaxName = false;
686
687
25
    int bufPos = 0;
688
689
25
    if (maxBufPos < 9)
690
0
        return 0;
691
692
25
    if (buffer[bufPos++] != 0x61)
693
0
        return 0;
694
695
25
    int len;
696
697
25
    bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
698
699
25
    if (bufPos < 0)
700
0
    {
701
0
        if (DEBUG_PRES)
702
0
            printf("PRES: invalid message!\n");
703
0
        return 0;
704
0
    }
705
706
25
    if (buffer[bufPos++] != 0x30)
707
0
        return 0;
708
709
25
    bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
710
711
25
    if (bufPos < 0)
712
0
    {
713
0
        if (DEBUG_PRES)
714
0
            printf("PRES: invalid message!\n");
715
0
        return 0;
716
0
    }
717
718
50
    while (bufPos + 1 < maxBufPos)
719
50
    {
720
50
        uint8_t tag = buffer[bufPos++];
721
50
        uint8_t lenField = buffer[bufPos];
722
723
50
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
724
725
50
        if (bufPos < 0)
726
0
        {
727
0
            if (DEBUG_PRES)
728
0
                printf("PRES: wrong parameter length\n");
729
0
            return 0;
730
0
        }
731
732
50
        switch (tag)
733
50
        {
734
25
        case 0x02: /* abstract-syntax-name */
735
25
            self->nextContextId = buffer[bufPos];
736
25
            hasAbstractSyntaxName = true;
737
25
            bufPos += len;
738
25
            break;
739
740
0
        case 0x06: /* transfer-syntax-name */
741
0
            {
742
                /* check if basic-encoding (2.1.1 - 51 01) */
743
0
                if (len < 2 || (buffer[bufPos] != 0x51) || (buffer[bufPos + 1] != 0x01))
744
0
                {
745
0
                    if (DEBUG_PRES)
746
0
                    {
747
0
                        printf("PRES: unknown transfer-syntax-name\n");
748
0
                    }
749
750
0
                    return 0;
751
0
                }
752
753
0
                bufPos += len;
754
0
            }
755
0
            break;
756
757
25
            case 0xa0: /* presentation data */
758
25
            {
759
25
                if (hasAbstractSyntaxName == false)
760
0
                {
761
0
                    if (DEBUG_PRES)
762
0
                        printf("PRES: abstract-syntax-name missing!\n");
763
764
0
                    return 0;
765
0
                }
766
767
25
                int userDataLength = len;
768
769
25
                if (lenField == 0x80)
770
0
                    userDataLength = userDataLength - 2;
771
772
25
                ByteBuffer_wrap(&(self->nextPayload), buffer + bufPos, userDataLength, userDataLength);
773
774
25
                return 1;
775
25
            }
776
0
            break;
777
50
        }
778
50
    }
779
780
0
    return 0;
781
25
}
782
783
int
784
IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer)
785
21
{
786
21
    uint8_t* buffer = byteBuffer->buffer;
787
21
    int maxBufPos = byteBuffer->size;
788
21
    bool hasNormalModeParameters = false;
789
790
21
    int bufPos = 0;
791
792
21
    if (maxBufPos < 1)
793
0
    {
794
0
        if (DEBUG_PRES)
795
0
            printf("PRES: invalid message!\n");
796
0
        return 0;
797
0
    }
798
799
21
    uint8_t cpTag = buffer[bufPos++];
800
801
21
    if (cpTag != 0x31)
802
0
    {
803
0
        if (DEBUG_PRES)
804
0
            printf("PRES: not a CP type\n");
805
0
        return 0;
806
0
    }
807
808
21
    int len;
809
810
21
    bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
811
812
21
    if (bufPos < 0)
813
0
    {
814
0
        if (DEBUG_PRES)
815
0
            printf("PRES: invalid message!\n");
816
0
        return 0;
817
0
    }
818
819
21
    if (DEBUG_PRES)
820
0
        printf("PRES: CPType with len %i\n", len);
821
822
63
    while (bufPos < maxBufPos)
823
42
    {
824
42
        uint8_t tag = buffer[bufPos++];
825
826
42
        bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
827
828
42
        if (bufPos < 0)
829
0
        {
830
0
            if (DEBUG_PRES)
831
0
                printf("PRES: invalid message!\n");
832
0
            return 0;
833
0
        }
834
835
42
        switch (tag)
836
42
        {
837
21
        case 0xa0: /* mode-selection */
838
21
            {
839
21
                if (len < 1 || buffer[bufPos++] != 0x80)
840
0
                {
841
0
                    if (DEBUG_PRES)
842
0
                        printf("PRES: mode-value of wrong type!\n");
843
0
                    return 0;
844
0
                }
845
846
21
                bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
847
848
21
                if (bufPos < 0)
849
0
                {
850
0
                    if (DEBUG_PRES)
851
0
                        printf("PRES: invalid message!\n");
852
0
                    return 0;
853
0
                }
854
855
21
                uint32_t modeSelector = BerDecoder_decodeUint32(buffer, len, bufPos);
856
857
21
                if (DEBUG_PRES)
858
0
                    printf("PRES: modesel %ui\n", modeSelector);
859
860
21
                bufPos += len;
861
21
            }
862
0
            break;
863
21
        case 0xa2: /* normal-mode-parameters */
864
21
            bufPos = parseNormalModeParameters(self, buffer, len, bufPos);
865
866
21
            if (bufPos < 0)
867
0
            {
868
0
                if (DEBUG_PRES)
869
0
                    printf("PRES: error parsing normal-mode-parameters\n");
870
0
                return 0;
871
0
            }
872
21
            else
873
21
            {
874
21
                hasNormalModeParameters = true;
875
21
            }
876
877
21
            break;
878
21
        case 0x00: /* indefinite length end tag -> ignore */
879
0
            break;
880
0
        default: /* unsupported element */
881
0
            if (DEBUG_PRES)
882
0
                printf("PRES: tag %i not recognized\n", tag);
883
0
            bufPos += len;
884
0
            break;
885
42
        }
886
42
    }
887
888
21
    if (hasNormalModeParameters == false)
889
0
    {
890
0
        if (DEBUG_PRES)
891
0
            printf("PRES: error - normal mode parameters are missing\n");
892
893
0
        return 0;
894
0
    }
895
896
21
    return 1;
897
21
}
898
899
void
900
IsoPresentation_createConnectPdu(IsoPresentation* self, IsoConnectionParameters parameters,
901
        BufferChain buffer, BufferChain payload)
902
21
{
903
21
    self->acseContextId = 1;
904
21
    self->mmsContextId = 3;
905
21
    self->callingPresentationSelector = parameters->localPSelector;
906
21
    self->calledPresentationSelector = parameters->remotePSelector;
907
21
    createConnectPdu(self, buffer, payload);
908
21
}
909
910
void
911
IsoPresentation_createAbortUserMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload)
912
0
{
913
0
    int contentLength = 0;
914
915
0
    contentLength += encodeUserData(NULL, 0, payload, false, self->acseContextId);
916
917
0
    uint8_t* buffer = writeBuffer->buffer;
918
0
    int bufPos = 0;
919
920
0
    bufPos = BerEncoder_encodeTL(0xa0, contentLength, buffer, bufPos);
921
922
    /* encode user data */
923
0
    bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId);
924
925
0
    writeBuffer->partLength = bufPos;
926
0
    writeBuffer->length = bufPos + payload->length;
927
0
    writeBuffer->nextPart = payload;
928
0
}
929
930
void
931
IsoPresentation_createCpaMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload)
932
21
{
933
21
    int contentLength = 0;
934
935
    /* mode-selector */
936
21
    contentLength += 5;
937
938
21
    int normalModeLength = 0;
939
940
21
    normalModeLength += 6; /* responding-presentation-selector */
941
942
21
    normalModeLength += 20; /* context-definition-result-list */
943
944
21
    normalModeLength += encodeUserData(NULL, 0, payload, false, self->acseContextId);
945
946
21
    contentLength += normalModeLength;
947
948
21
    contentLength += BerEncoder_determineLengthSize(normalModeLength) + 1;
949
950
21
    uint8_t* buffer = writeBuffer->buffer;
951
21
    int bufPos = 0;
952
953
21
    bufPos = BerEncoder_encodeTL(0x31, contentLength, buffer, bufPos);
954
955
    /* mode-selector */
956
21
    bufPos = BerEncoder_encodeTL(0xa0, 3, buffer, bufPos);
957
21
    bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos);
958
21
    buffer[bufPos++] = 1; /* 1 = normal-mode */
959
960
    /* normal-mode-parameters */
961
21
    bufPos = BerEncoder_encodeTL(0xa2, normalModeLength, buffer, bufPos);
962
963
    /* responding-presentation-selector */
964
21
    bufPos = BerEncoder_encodeTL(0x83, 4, buffer, bufPos);
965
21
    memcpy(buffer + bufPos, calledPresentationSelector, 4);
966
21
    bufPos += 4;
967
968
    /* context-definition-result-list */
969
21
    bufPos = BerEncoder_encodeTL(0xa5, 18, buffer, bufPos);
970
21
    bufPos = encodeAcceptBer(buffer, bufPos); /* accept for acse */
971
21
    bufPos = encodeAcceptBer(buffer, bufPos); /* accept for mms */
972
973
    /* encode user data */
974
21
    bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId);
975
976
21
    writeBuffer->partLength = bufPos;
977
21
    writeBuffer->length = bufPos + payload->length;
978
21
    writeBuffer->nextPart = payload;
979
21
}