-
Notifications
You must be signed in to change notification settings - Fork 313
/
Copy pathil2p_header.c
679 lines (552 loc) · 22.4 KB
/
il2p_header.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2021 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include "direwolf.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "textcolor.h"
#include "ax25_pad.h"
#include "ax25_pad2.h"
#include "il2p.h"
/*--------------------------------------------------------------------------------
*
* File: il2p_header.c
*
* Purpose: Functions to deal with the IL2P header.
*
* Reference: http://tarpn.net/t/il2p/il2p-specification0-4.pdf
*
*--------------------------------------------------------------------------------*/
// Convert ASCII to/from DEC SIXBIT as defined here:
// https://en.wikipedia.org/wiki/Six-bit_character_code#DEC_six-bit_code
static inline int ascii_to_sixbit (int a)
{
if (a >= ' ' && a <= '_') return (a - ' ');
return (31); // '?' for any invalid.
}
static inline int sixbit_to_ascii (int s)
{
return (s + ' ');
}
// Functions for setting the various header fields.
// It is assumed that it was zeroed first so only the '1' bits are set.
static void set_field (unsigned char *hdr, int bit_num, int lsb_index, int width, int value)
{
while (width > 0 && value != 0) {
assert (lsb_index >= 0 && lsb_index <= 11);
if (value & 1) {
hdr[lsb_index] |= 1 << bit_num;
}
value >>= 1;
lsb_index--;
width--;
}
assert (value == 0);
}
#define SET_UI(hdr,val) set_field(hdr, 6, 0, 1, val)
#define SET_PID(hdr,val) set_field(hdr, 6, 4, 4, val)
#define SET_CONTROL(hdr,val) set_field(hdr, 6, 11, 7, val)
#define SET_FEC_LEVEL(hdr,val) set_field(hdr, 7, 0, 1, val)
#define SET_HDR_TYPE(hdr,val) set_field(hdr, 7, 1, 1, val)
#define SET_PAYLOAD_BYTE_COUNT(hdr,val) set_field(hdr, 7, 11, 10, val)
// Extracting the fields.
static int get_field (unsigned char *hdr, int bit_num, int lsb_index, int width)
{
int result = 0;
lsb_index -= width - 1;
while (width > 0) {
result <<= 1;
assert (lsb_index >= 0 && lsb_index <= 11);
if (hdr[lsb_index] & (1 << bit_num)) {
result |= 1;
}
lsb_index++;
width--;
}
return (result);
}
#define GET_UI(hdr) get_field(hdr, 6, 0, 1)
#define GET_PID(hdr) get_field(hdr, 6, 4, 4)
#define GET_CONTROL(hdr) get_field(hdr, 6, 11, 7)
#define GET_FEC_LEVEL(hdr) get_field(hdr, 7, 0, 1)
#define GET_HDR_TYPE(hdr) get_field(hdr, 7, 1, 1)
#define GET_PAYLOAD_BYTE_COUNT(hdr) get_field(hdr, 7, 11, 10)
// AX.25 'I' and 'UI' frames have a protocol ID which determines how the
// information part should be interpreted.
// Here we squeeze the most common cases down to 4 bits.
// Return -1 if translation is not possible. Fall back to type 0 header in this case.
static int encode_pid (packet_t pp)
{
int pid = ax25_get_pid(pp);
if ((pid & 0x30) == 0x20) return (0x2); // AX.25 Layer 3
if ((pid & 0x30) == 0x10) return (0x2); // AX.25 Layer 3
if (pid == 0x01) return (0x3); // ISO 8208 / CCIT X.25 PLP
if (pid == 0x06) return (0x4); // Compressed TCP/IP
if (pid == 0x07) return (0x5); // Uncompressed TCP/IP
if (pid == 0x08) return (0x6); // Segmentation fragmen
if (pid == 0xcc) return (0xb); // ARPA Internet Protocol
if (pid == 0xcd) return (0xc); // ARPA Address Resolution
if (pid == 0xce) return (0xd); // FlexNet
if (pid == 0xcf) return (0xe); // TheNET
if (pid == 0xf0) return (0xf); // No L3
return (-1);
}
// Convert IL2P 4 bit PID to AX.25 8 bit PID.
static int decode_pid (int pid)
{
static const unsigned char axpid[16] = {
0xf0, // Should not happen. 0 is for 'S' frames.
0xf0, // Should not happen. 1 is for 'U' frames (but not UI).
0x20, // AX.25 Layer 3
0x01, // ISO 8208 / CCIT X.25 PLP
0x06, // Compressed TCP/IP
0x07, // Uncompressed TCP/IP
0x08, // Segmentation fragment
0xf0, // Future
0xf0, // Future
0xf0, // Future
0xf0, // Future
0xcc, // ARPA Internet Protocol
0xcd, // ARPA Address Resolution
0xce, // FlexNet
0xcf, // TheNET
0xf0 }; // No L3
assert (pid >= 0 && pid <= 15);
return (axpid[pid]);
}
/*--------------------------------------------------------------------------------
*
* Function: il2p_type_1_header
*
* Purpose: Attempt to create type 1 header from packet object.
*
* Inputs: pp - Packet object.
*
* max_fec - 1 to use maximum FEC symbols , 0 for automatic.
*
* Outputs: hdr - IL2P header with no scrambling or parity symbols.
* Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes.
*
* Returns: Number of bytes for information part or -1 for failure.
* In case of failure, fall back to type 0 transparent encapsulation.
*
* Description: Type 1 Headers do not support AX.25 repeater callsign addressing,
* Modulo-128 extended mode window sequence numbers, nor any callsign
* characters that cannot translate to DEC SIXBIT.
* If these cases are encountered during IL2P packet encoding,
* the encoder switches to Type 0 Transparent Encapsulation.
* SABME can't be handled by type 1.
*
*--------------------------------------------------------------------------------*/
int il2p_type_1_header (packet_t pp, int max_fec, unsigned char *hdr)
{
memset (hdr, 0, IL2P_HEADER_SIZE);
if (ax25_get_num_addr(pp) != 2) {
// Only two addresses are allowed for type 1 header.
return (-1);
}
// Check does not apply for 'U' frames but put in one place rather than two.
if (ax25_get_modulo(pp) == 128) return(-1);
// Destination and source addresses go into low bits 0-5 for bytes 0-11.
char dst_addr[AX25_MAX_ADDR_LEN];
char src_addr[AX25_MAX_ADDR_LEN];
ax25_get_addr_no_ssid (pp, AX25_DESTINATION, dst_addr);
int dst_ssid = ax25_get_ssid (pp, AX25_DESTINATION);
ax25_get_addr_no_ssid (pp, AX25_SOURCE, src_addr);
int src_ssid = ax25_get_ssid (pp, AX25_SOURCE);
unsigned char *a = (unsigned char *)dst_addr;
for (int i = 0; *a != '\0'; i++, a++) {
if (*a < ' ' || *a > '_') {
// Shouldn't happen but follow the rule.
return (-1);
}
hdr[i] = ascii_to_sixbit(*a);
}
a = (unsigned char *)src_addr;
for (int i = 6; *a != '\0'; i++, a++) {
if (*a < ' ' || *a > '_') {
// Shouldn't happen but follow the rule.
return (-1);
}
hdr[i] = ascii_to_sixbit(*a);
}
// Byte 12 has DEST SSID in upper nybble and SRC SSID in lower nybble and
hdr[12] = (dst_ssid << 4) | src_ssid;
ax25_frame_type_t frame_type;
cmdres_t cr; // command or response.
char description[64];
int pf; // Poll/Final.
int nr, ns; // Sequence numbers.
frame_type = ax25_frame_type (pp, &cr, description, &pf, &nr, &ns);
//dw_printf ("%s(): %s-%d>%s-%d: %s\n", __func__, src_addr, src_ssid, dst_addr, dst_ssid, description);
switch (frame_type) {
case frame_type_S_RR: // Receive Ready - System Ready To Receive
case frame_type_S_RNR: // Receive Not Ready - TNC Buffer Full
case frame_type_S_REJ: // Reject Frame - Out of Sequence or Duplicate
case frame_type_S_SREJ: // Selective Reject - Request single frame repeat
// S frames (RR, RNR, REJ, SREJ), mod 8, have control N(R) P/F S S 0 1
// These are mapped into P/F N(R) C S S
// Bit 6 is not mentioned in documentation but it is used for P/F for the other frame types.
// C is copied from the C bit in the destination addr.
// C from source is not used here. Reception assumes it is the opposite.
// PID is set to 0, meaning none, for S frames.
SET_UI(hdr, 0);
SET_PID(hdr, 0);
SET_CONTROL(hdr, (pf<<6) | (nr<<3) | (((cr == cr_cmd) | (cr == cr_11))<<2));
// This gets OR'ed into the above.
switch (frame_type) {
case frame_type_S_RR: SET_CONTROL(hdr, 0); break;
case frame_type_S_RNR: SET_CONTROL(hdr, 1); break;
case frame_type_S_REJ: SET_CONTROL(hdr, 2); break;
case frame_type_S_SREJ: SET_CONTROL(hdr, 3); break;
default: break;
}
break;
case frame_type_U_SABM: // Set Async Balanced Mode
case frame_type_U_DISC: // Disconnect
case frame_type_U_DM: // Disconnect Mode
case frame_type_U_UA: // Unnumbered Acknowledge
case frame_type_U_FRMR: // Frame Reject
case frame_type_U_UI: // Unnumbered Information
case frame_type_U_XID: // Exchange Identification
case frame_type_U_TEST: // Test
// The encoding allows only 3 bits for frame type and SABME got left out.
// Control format: P/F opcode[3] C n/a n/a
// The grayed out n/a bits are observed as 00 in the example.
// The header UI field must also be set for UI frames.
// PID is set to 1 for all U frames other than UI.
if (frame_type == frame_type_U_UI) {
SET_UI(hdr, 1); // I guess this is how we distinguish 'I' and 'UI'
// on the receiving end.
int pid = encode_pid(pp);
if (pid < 0) return (-1);
SET_PID(hdr, pid);
}
else {
SET_PID(hdr, 1); // 1 for 'U' other than 'UI'.
}
// Each of the destination and source addresses has a "C" bit.
// They should normally have the opposite setting.
// IL2P has only a single bit to represent 4 possbilities.
//
// dst src il2p meaning
// --- --- ---- -------
// 0 0 0 Not valid (earlier protocol version)
// 1 0 1 Command (v2)
// 0 1 0 Response (v2)
// 1 1 1 Not valid (earlier protocol version)
//
// APRS does not mention how to set these bits and all 4 combinations
// are seen in the wild. Apparently these are ignored on receive and no
// one cares. Here we copy from the C bit in the destination address.
// It should be noted that the case of both C bits being the same can't
// be represented so the il2p encode/decode bit not produce exactly the
// same bits. We see this in the second example in the protocol spec.
// The original UI frame has both C bits of 0 so it is received as a response.
SET_CONTROL(hdr, (pf<<6) | (((cr == cr_cmd) | (cr == cr_11))<<2));
// This gets OR'ed into the above.
switch (frame_type) {
case frame_type_U_SABM: SET_CONTROL(hdr, 0<<3); break;
case frame_type_U_DISC: SET_CONTROL(hdr, 1<<3); break;
case frame_type_U_DM: SET_CONTROL(hdr, 2<<3); break;
case frame_type_U_UA: SET_CONTROL(hdr, 3<<3); break;
case frame_type_U_FRMR: SET_CONTROL(hdr, 4<<3); break;
case frame_type_U_UI: SET_CONTROL(hdr, 5<<3); break;
case frame_type_U_XID: SET_CONTROL(hdr, 6<<3); break;
case frame_type_U_TEST: SET_CONTROL(hdr, 7<<3); break;
default: break;
}
break;
case frame_type_I: // Information
// I frames (mod 8 only)
// encoded control: P/F N(R) N(S)
SET_UI(hdr, 0);
int pid2 = encode_pid(pp);
if (pid2 < 0) return (-1);
SET_PID(hdr, pid2);
SET_CONTROL(hdr, (pf<<6) | (nr<<3) | ns);
break;
case frame_type_U_SABME: // Set Async Balanced Mode, Extended
case frame_type_U: // other Unnumbered, not used by AX.25.
case frame_not_AX25: // Could not get control byte from frame.
default:
// Fall back to the header type 0 for these.
return (-1);
}
// Common for all header type 1.
// Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10]
SET_FEC_LEVEL(hdr, max_fec);
SET_HDR_TYPE(hdr, 1);
unsigned char *pinfo;
int info_len;
info_len = ax25_get_info (pp, &pinfo);
if (info_len < 0 || info_len > IL2P_MAX_PAYLOAD_SIZE) {
return (-2);
}
SET_PAYLOAD_BYTE_COUNT(hdr, info_len);
return (info_len);
}
// This should create a packet from the IL2P header.
// The information part will not be filled in.
static void trim (char *stuff)
{
char *p = stuff + strlen(stuff) - 1;
while (strlen(stuff) > 0 && (*p == ' ')) {
*p = '\0';
p--;
}
}
/*--------------------------------------------------------------------------------
*
* Function: il2p_decode_header_type_1
*
* Purpose: Attempt to convert type 1 header to a packet object.
*
* Inputs: hdr - IL2P header with no scrambling or parity symbols.
*
* num_sym_changed - Number of symbols changed by FEC in the header.
* Should be 0 or 1.
*
* Returns: Packet Object or NULL for failure.
*
* Description: A later step will process the payload for the information part.
*
*--------------------------------------------------------------------------------*/
packet_t il2p_decode_header_type_1 (unsigned char *hdr, int num_sym_changed)
{
if (GET_HDR_TYPE(hdr) != 1 ) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("IL2P Internal error. Should not be here: %s, when header type is 0.\n", __func__);
return (NULL);
}
// First get the addresses including SSID.
char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
int num_addr = 2;
memset (addrs, 0, 2*AX25_MAX_ADDR_LEN);
// The IL2P header uses 2 parity symbols which means a single corrupted symbol (byte)
// can always be corrected.
// However, I have seen cases, where the error rate is very high, where the RS decoder
// thinks it found a valid code block by changing one symbol but it was the wrong one.
// The result is trash. This shows up as address fields like 'R&G4"A' and 'TEW\ !'.
// I added a sanity check here to catch characters other than upper case letters and digits.
// The frame should be rejected in this case. The question is whether to discard it
// silently or print a message so the user can see that something strange is happening?
// My current thinking is that it should be silently ignored if the header has been
// modified (correctee or more likely, made worse in this cases).
// If no changes were made, something weird is happening. We should mention it for
// troubleshooting rather than sweeping it under the rug.
// The same thing has been observed with the payload, under very high error conditions,
// and max_fec==0. Here I don't see a good solution. AX.25 information can contain
// "binary" data so I'm not sure what sort of sanity check could be added.
// This was not observed with max_fec==1. If we make that the default, same as Nino TNC,
// it would be extremely extremely unlikely unless someone explicitly selects weaker FEC.
// TODO: We could do something similar for header type 0.
// The address fields should be all binary zero values.
// Someone overly ambitious might check the addresses found in the first payload block.
for (int i = 0; i <= 5; i++) {
addrs[AX25_DESTINATION][i] = sixbit_to_ascii(hdr[i] & 0x3f);
}
trim (addrs[AX25_DESTINATION]);
for (int i = 0; i < strlen(addrs[AX25_DESTINATION]); i++) {
if (! isupper(addrs[AX25_DESTINATION][i]) && ! isdigit(addrs[AX25_DESTINATION][i])) {
if (num_sym_changed == 0) {
// This can pop up sporadically when receiving random noise.
// Would be better to show only when debug is enabled but variable not available here.
// TODO: For now we will just suppress it.
//text_color_set(DW_COLOR_ERROR);
//dw_printf ("IL2P: Invalid character '%c' in destination address '%s'\n", addrs[AX25_DESTINATION][i], addrs[AX25_DESTINATION]);
}
return (NULL);
}
}
snprintf (addrs[AX25_DESTINATION]+strlen(addrs[AX25_DESTINATION]), 4, "-%d", (hdr[12] >> 4) &0xf);
for (int i = 0; i <= 5; i++) {
addrs[AX25_SOURCE][i] = sixbit_to_ascii(hdr[i+6] & 0x3f);
}
trim (addrs[AX25_SOURCE]);
for (int i = 0; i < strlen(addrs[AX25_SOURCE]); i++) {
if (! isupper(addrs[AX25_SOURCE][i]) && ! isdigit(addrs[AX25_SOURCE][i])) {
if (num_sym_changed == 0) {
// This can pop up sporadically when receiving random noise.
// Would be better to show only when debug is enabled but variable not available here.
// TODO: For now we will just suppress it.
//text_color_set(DW_COLOR_ERROR);
//dw_printf ("IL2P: Invalid character '%c' in source address '%s'\n", addrs[AX25_SOURCE][i], addrs[AX25_SOURCE]);
}
return (NULL);
}
}
snprintf (addrs[AX25_SOURCE]+strlen(addrs[AX25_SOURCE]), 4, "-%d", hdr[12] &0xf);
// The PID field gives us the general type.
// 0 = 'S' frame.
// 1 = 'U' frame other than UI.
// others are either 'UI' or 'I' depending on the UI field.
int pid = GET_PID(hdr);
int ui = GET_UI(hdr);
if (pid == 0) {
// 'S' frame.
// The control field contains: P/F N(R) C S S
int control = GET_CONTROL(hdr);
cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
ax25_frame_type_t ftype;
switch (control & 0x03) {
case 0: ftype = frame_type_S_RR; break;
case 1: ftype = frame_type_S_RNR; break;
case 2: ftype = frame_type_S_REJ; break;
default: ftype = frame_type_S_SREJ; break;
}
int modulo = 8;
int nr = (control >> 3) & 0x07;
int pf = (control >> 6) & 0x01;
unsigned char *pinfo = NULL; // Any info for SREJ will be added later.
int info_len = 0;
return (ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf, pinfo, info_len));
}
else if (pid == 1) {
// 'U' frame other than 'UI'.
// The control field contains: P/F OPCODE{3) C x x
int control = GET_CONTROL(hdr);
cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
int axpid = 0; // unused for U other than UI.
ax25_frame_type_t ftype;
switch ((control >> 3) & 0x7) {
case 0: ftype = frame_type_U_SABM; break;
case 1: ftype = frame_type_U_DISC; break;
case 2: ftype = frame_type_U_DM; break;
case 3: ftype = frame_type_U_UA; break;
case 4: ftype = frame_type_U_FRMR; break;
case 5: ftype = frame_type_U_UI; axpid = 0xf0; break; // Should not happen with IL2P pid == 1.
case 6: ftype = frame_type_U_XID; break;
default: ftype = frame_type_U_TEST; break;
}
int pf = (control >> 6) & 0x01;
unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later.
int info_len = 0;
return (ax25_u_frame (addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len));
}
else if (ui) {
// 'UI' frame.
// The control field contains: P/F OPCODE{3) C x x
int control = GET_CONTROL(hdr);
cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
ax25_frame_type_t ftype = frame_type_U_UI;
int pf = (control >> 6) & 0x01;
int axpid = decode_pid(GET_PID(hdr));
unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later.
int info_len = 0;
return (ax25_u_frame (addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len));
}
else {
// 'I' frame.
// The control field contains: P/F N(R) N(S)
int control = GET_CONTROL(hdr);
cmdres_t cr = cr_cmd; // Always command.
int pf = (control >> 6) & 0x01;
int nr = (control >> 3) & 0x7;
int ns = control & 0x7;
int modulo = 8;
int axpid = decode_pid(GET_PID(hdr));
unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later.
int info_len = 0;
return (ax25_i_frame (addrs, num_addr, cr, modulo, nr, ns, pf, axpid, pinfo, info_len));
}
return (NULL); // unreachable but avoid warning.
} // end
/*--------------------------------------------------------------------------------
*
* Function: il2p_type_0_header
*
* Purpose: Attempt to create type 0 header from packet object.
*
* Inputs: pp - Packet object.
*
* max_fec - 1 to use maximum FEC symbols, 0 for automatic.
*
* Outputs: hdr - IL2P header with no scrambling or parity symbols.
* Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes.
*
* Returns: Number of bytes for information part or -1 for failure.
* In case of failure, fall back to type 0 transparent encapsulation.
*
* Description: The type 0 header is used when it is not one of the restricted cases
* covered by the type 1 header.
* The AX.25 frame is put in the payload.
* This will cover: more than one address, mod 128 sequences, etc.
*
*--------------------------------------------------------------------------------*/
int il2p_type_0_header (packet_t pp, int max_fec, unsigned char *hdr)
{
memset (hdr, 0, IL2P_HEADER_SIZE);
// Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10]
SET_FEC_LEVEL(hdr, max_fec);
SET_HDR_TYPE(hdr, 0);
int frame_len = ax25_get_frame_len (pp);
if (frame_len < 14 || frame_len > IL2P_MAX_PAYLOAD_SIZE) {
return (-2);
}
SET_PAYLOAD_BYTE_COUNT(hdr, frame_len);
return (frame_len);
}
/***********************************************************************************
*
* Name: il2p_get_header_attributes
*
* Purpose: Extract a few attributes from an IL2p header.
*
* Inputs: hdr - IL2P header structure.
*
* Outputs: hdr_type - 0 or 1.
*
* max_fec - 0 for automatic or 1 for fixed maximum size.
*
* Returns: Payload byte count. (actual payload size, not the larger encoded format)
*
***********************************************************************************/
int il2p_get_header_attributes (unsigned char *hdr, int *hdr_type, int *max_fec)
{
*hdr_type = GET_HDR_TYPE(hdr);
*max_fec = GET_FEC_LEVEL(hdr);
return(GET_PAYLOAD_BYTE_COUNT(hdr));
}
/***********************************************************************************
*
* Name: il2p_clarify_header
*
* Purpose: Convert received header to usable form.
* This involves RS FEC then descrambling.
*
* Inputs: rec_hdr - Header as received over the radio.
*
* Outputs: corrected_descrambled_hdr - After RS FEC and unscrambling.
*
* Returns: Number of symbols that were corrected:
* 0 = No errors
* 1 = Single symbol corrected.
* <0 = Unable to obtain good header.
*
***********************************************************************************/
int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr)
{
unsigned char corrected[IL2P_HEADER_SIZE+IL2P_HEADER_PARITY];
int e = il2p_decode_rs (rec_hdr, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, corrected);
il2p_descramble_block (corrected, corrected_descrambled_hdr, IL2P_HEADER_SIZE);
return (e);
}
// end il2p_header.c