/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 | } |