1 //
2 // This file is part of Dire Wolf, an amateur radio packet TNC.
3 //
4 // Copyright (C) 2011 , 2013, 2014, 2015, 2019 John Langner, WB2OSZ
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19
20
21 /*------------------------------------------------------------------
22 *
23 * Name: ax25_pad
24 *
25 * Purpose: Packet assembler and disasembler.
26 *
27 * This was written when I was only concerned about APRS which
28 * uses only UI frames. ax25_pad2.c, added years later, has
29 * functions for dealing with other types of frames.
30 *
31 * We can obtain AX.25 packets from different sources:
32 *
33 * (a) from an HDLC frame.
34 * (b) from text representation.
35 * (c) built up piece by piece.
36 *
37 * We also want to use a packet in different ways:
38 *
39 * (a) transmit as an HDLC frame.
40 * (b) print in human-readable text.
41 * (c) take it apart piece by piece.
42 *
43 * Looking at the more general case, we also want to modify
44 * an existing packet. For instance an APRS repeater might
45 * want to change "WIDE2-2" to "WIDE2-1" and retransmit it.
46 *
47 *
48 * Description:
49 *
50 *
51 * APRS uses only UI frames.
52 * Each starts with 2-10 addressses (14-70 octets):
53 *
54 * * Destination Address (note: opposite order in printed format)
55 *
56 * * Source Address
57 *
58 * * 0-8 Digipeater Addresses (Could there ever be more as a result of
59 * digipeaters inserting their own call for
60 * the tracing feature?
61 * NO. The limit is 8 when transmitting AX.25 over the
62 * radio.
63 * Communication with an IGate server could
64 * have a longer VIA path but that is only in text form,
65 * not as an AX.25 frame.)
66 *
67 * Each address is composed of:
68 *
69 * * 6 upper case letters or digits, blank padded.
70 * These are shifted left one bit, leaving the LSB always 0.
71 *
72 * * a 7th octet containing the SSID and flags.
73 * The LSB is always 0 except for the last octet of the address field.
74 *
75 * The final octet of the Destination has the form:
76 *
77 * C R R SSID 0, where,
78 *
79 * C = command/response = 1
80 * R R = Reserved = 1 1
81 * SSID = substation ID
82 * 0 = zero
83 *
84 * The AX.25 spec states that the RR bits should be 11 if not used.
85 * There are a couple documents talking about possible uses for APRS.
86 * I'm ignoring them for now.
87 * http://www.aprs.org/aprs12/preemptive-digipeating.txt
88 * http://www.aprs.org/aprs12/RR-bits.txt
89 *
90 * I don't recall why I originally set the source & destination C bits both to 1.
91 * Reviewing this 5 years later, after spending more time delving into the
92 * AX.25 spec, I think it should be 1 for destination and 0 for source.
93 * In practice you see all four combinations being used by APRS stations
94 * and everyone apparently ignores them for APRS. They do make a big
95 * difference for connected mode.
96 *
97 * The final octet of the Source has the form:
98 *
99 * C R R SSID 0, where,
100 *
101 * C = command/response = 0
102 * R R = Reserved = 1 1
103 * SSID = substation ID
104 * 0 = zero (or 1 if no repeaters)
105 *
106 * The final octet of each repeater has the form:
107 *
108 * H R R SSID 0, where,
109 *
110 * H = has-been-repeated = 0 initially.
111 * Set to 1 after this address has been used.
112 * R R = Reserved = 1 1
113 * SSID = substation ID
114 * 0 = zero (or 1 if last repeater in list)
115 *
116 * A digipeater would repeat this frame if it finds its address
117 * with the "H" bit set to 0 and all earlier repeater addresses
118 * have the "H" bit set to 1.
119 * The "H" bit would be set to 1 in the repeated frame.
120 *
121 * In standard monitoring format, an asterisk is displayed after the last
122 * digipeater with the "H" bit set. That indicates who you are hearing
123 * over the radio.
124 * (That is if digipeaters update the via path properly. Some don't so
125 * we don't know who we are hearing. This is discussed in the User Guide.)
126 * No asterisk means the source is being heard directly.
127 *
128 * Example, if we can hear all stations involved,
129 *
130 * SRC>DST,RPT1,RPT2,RPT3: -- we heard SRC
131 * SRC>DST,RPT1*,RPT2,RPT3: -- we heard RPT1
132 * SRC>DST,RPT1,RPT2*,RPT3: -- we heard RPT2
133 * SRC>DST,RPT1,RPT2,RPT3*: -- we heard RPT3
134 *
135 *
136 * Next we have:
137 *
138 * * One byte Control Field - APRS uses 3 for UI frame
139 * The more general AX.25 frame can have two.
140 *
141 * * One byte Protocol ID - APRS uses 0xf0 for no layer 3
142 *
143 * Finally the Information Field of 1-256 bytes.
144 *
145 * And, of course, the 2 byte CRC.
146 *
147 * The descriptions above, for the C, H, and RR bits, are for APRS usage.
148 * When operating as a KISS TNC we just pass everything along and don't
149 * interpret or change them.
150 *
151 *
152 * Constructors: ax25_init - Clear everything.
153 * ax25_from_text - Tear apart a text string
154 * ax25_from_frame - Tear apart an AX.25 frame.
155 * Must be called before any other function.
156 *
157 * Get methods: .... - Extract destination, source, or digipeater
158 * address from frame.
159 *
160 * Assumptions: CRC has already been verified to be correct.
161 *
162 *------------------------------------------------------------------*/
163
164 #define AX25_PAD_C /* this will affect behavior of ax25_pad.h */
165
166 #include "direwolf.h"
167
168 #include <stdlib.h>
169 #include <string.h>
170 #include <assert.h>
171 #include <stdio.h>
172 #include <ctype.h>
173
174 #include "regex.h"
175
176 #if __WIN32__
177 char *strtok_r(char *str, const char *delim, char **saveptr);
178 #endif
179
180
181 #include "textcolor.h"
182 #include "ax25_pad.h"
183 #include "fcs_calc.h"
184
185 /*
186 * Accumulate statistics.
187 * If new_count gets much larger than delete_count plus the size of
188 * the transmit queue we have a memory leak.
189 */
190
191 static volatile int new_count = 0;
192 static volatile int delete_count = 0;
193 static volatile int last_seq_num = 0;
194
195 #if AX25MEMDEBUG
196
197 int ax25memdebug = 0;
198
199
ax25memdebug_set(void)200 void ax25memdebug_set(void)
201 {
202 ax25memdebug = 1;
203 }
204
ax25memdebug_get(void)205 int ax25memdebug_get (void)
206 {
207 return (ax25memdebug);
208 }
209
ax25memdebug_seq(packet_t this_p)210 int ax25memdebug_seq (packet_t this_p)
211 {
212 return (this_p->seq);
213 }
214
215
216 #endif
217
218
219
220 #define CLEAR_LAST_ADDR_FLAG this_p->frame_data[this_p->num_addr*7-1] &= ~ SSID_LAST_MASK
221 #define SET_LAST_ADDR_FLAG this_p->frame_data[this_p->num_addr*7-1] |= SSID_LAST_MASK
222
223
224 /*------------------------------------------------------------------------------
225 *
226 * Name: ax25_new
227 *
228 * Purpose: Allocate memory for a new packet object.
229 *
230 * Returns: Identifier for a new packet object.
231 * In the current implementation this happens to be a pointer.
232 *
233 *------------------------------------------------------------------------------*/
234
235
ax25_new(void)236 packet_t ax25_new (void)
237 {
238 struct packet_s *this_p;
239
240
241 #if DEBUG
242 text_color_set(DW_COLOR_DEBUG);
243 dw_printf ("ax25_new(): before alloc, new=%d, delete=%d\n", new_count, delete_count);
244 #endif
245
246 last_seq_num++;
247 new_count++;
248
249 /*
250 * check for memory leak.
251 */
252
253 // version 1.4 push up the threshold. We could have considerably more with connected mode.
254
255 //if (new_count > delete_count + 100) {
256 if (new_count > delete_count + 256) {
257
258
259 text_color_set(DW_COLOR_ERROR);
260 dw_printf ("Report to WB2OSZ - Memory leak for packet objects. new=%d, delete=%d\n", new_count, delete_count);
261 #if AX25MEMDEBUG
262 // Force on debug option to gather evidence.
263 ax25memdebug_set();
264 #endif
265 }
266
267 this_p = calloc(sizeof (struct packet_s), (size_t)1);
268
269 if (this_p == NULL) {
270 text_color_set(DW_COLOR_ERROR);
271 dw_printf ("ERROR - can't allocate memory in ax25_new.\n");
272 }
273
274 assert (this_p != NULL);
275
276 this_p->magic1 = MAGIC;
277 this_p->seq = last_seq_num;
278 this_p->magic2 = MAGIC;
279 this_p->num_addr = (-1);
280
281 return (this_p);
282 }
283
284 /*------------------------------------------------------------------------------
285 *
286 * Name: ax25_delete
287 *
288 * Purpose: Destroy a packet object, freeing up memory it was using.
289 *
290 *------------------------------------------------------------------------------*/
291
292 #if AX25MEMDEBUG
ax25_delete_debug(packet_t this_p,char * src_file,int src_line)293 void ax25_delete_debug (packet_t this_p, char *src_file, int src_line)
294 #else
295 void ax25_delete (packet_t this_p)
296 #endif
297 {
298 #if DEBUG
299 text_color_set(DW_COLOR_DEBUG);
300 dw_printf ("ax25_delete(): before free, new=%d, delete=%d\n", new_count, delete_count);
301 #endif
302
303 if (this_p == NULL) {
304 text_color_set(DW_COLOR_ERROR);
305 dw_printf ("ERROR - NULL pointer passed to ax25_delete.\n");
306 return;
307 }
308
309
310 delete_count++;
311
312 #if AX25MEMDEBUG
313 if (ax25memdebug) {
314 text_color_set(DW_COLOR_DEBUG);
315 dw_printf ("ax25_delete, seq=%d, called from %s %d, new_count=%d, delete_count=%d\n", this_p->seq, src_file, src_line, new_count, delete_count);
316 }
317 #endif
318
319 assert (this_p->magic1 == MAGIC);
320 assert (this_p->magic2 == MAGIC);
321
322 this_p->magic1 = 0;
323 this_p->magic1 = 0;
324
325 //memset (this_p, 0, sizeof (struct packet_s));
326 free (this_p);
327 }
328
329
330
331 /*------------------------------------------------------------------------------
332 *
333 * Name: ax25_from_text
334 *
335 * Purpose: Parse a frame in human-readable monitoring format and change
336 * to internal representation.
337 *
338 * Input: monitor - "TNC-2" monitor format for packet. i.e.
339 * source>dest[,repeater1,repeater2,...]:information
340 *
341 * The information part can have non-printable characters
342 * in the form of <0xff>. This will be converted to single
343 * bytes. e.g. <0x0d> is carriage return.
344 * In version 1.4H we will allow nul characters which means
345 * we have to maintain a length rather than using strlen().
346 * I maintain that it violates the spec but want to handle it
347 * because it does happen and we want to preserve it when
348 * acting as an IGate rather than corrupting it.
349 *
350 * strict - True to enforce rules for packets sent over the air.
351 * False to be more lenient for packets from IGate server.
352 *
353 * Messages from an IGate server can have longer
354 * addresses after qAC. Up to 9 observed so far.
355 *
356 * We can just truncate the name because we will only
357 * end up discarding it. TODO: check on this.
358 *
359 * Returns: Pointer to new packet object in the current implementation.
360 *
361 * Outputs: Use the "get" functions to retrieve information in different ways.
362 *
363 *------------------------------------------------------------------------------*/
364
365 #if AX25MEMDEBUG
ax25_from_text_debug(char * monitor,int strict,char * src_file,int src_line)366 packet_t ax25_from_text_debug (char *monitor, int strict, char *src_file, int src_line)
367 #else
368 packet_t ax25_from_text (char *monitor, int strict)
369 #endif
370 {
371
372 /*
373 * Tearing it apart is destructive so make our own copy first.
374 */
375 char stuff[512];
376 char *pinfo;
377
378 int ssid_temp, heard_temp;
379 char atemp[AX25_MAX_ADDR_LEN];
380
381 char info_part[AX25_MAX_INFO_LEN+1];
382 int info_len;
383
384 // text_color_set(DW_COLOR_DEBUG);
385 // dw_printf ("DEBUG: ax25_from_text ('%s', %d)\n", monitor, strict);
386 // fflush(stdout); sleep(1);
387
388 packet_t this_p = ax25_new ();
389
390 #if AX25MEMDEBUG
391 if (ax25memdebug) {
392 text_color_set(DW_COLOR_DEBUG);
393 dw_printf ("ax25_from_text, seq=%d, called from %s %d\n", this_p->seq, src_file, src_line);
394 }
395 #endif
396
397 /* Is it possible to have a nul character (zero byte) in the */
398 /* information field of an AX.25 frame? */
399 /* At this point, we have a normal C string. */
400 /* It is possible that will convert <0x00> to a nul character later. */
401 /* There we need to maintain a separate length and not use normal C string functions. */
402
403 strlcpy (stuff, monitor, sizeof(stuff));
404
405
406 /*
407 * Initialize the packet structure with two addresses and control/pid
408 * for APRS.
409 */
410 memset (this_p->frame_data + AX25_DESTINATION*7, ' ' << 1, 6);
411 this_p->frame_data[AX25_DESTINATION*7+6] = SSID_H_MASK | SSID_RR_MASK;
412
413 memset (this_p->frame_data + AX25_SOURCE*7, ' ' << 1, 6);
414 this_p->frame_data[AX25_SOURCE*7+6] = SSID_RR_MASK | SSID_LAST_MASK;
415
416 this_p->frame_data[14] = AX25_UI_FRAME;
417 this_p->frame_data[15] = AX25_PID_NO_LAYER_3;
418
419 this_p->frame_len = 7 + 7 + 1 + 1;
420 this_p->num_addr = (-1);
421 (void) ax25_get_num_addr(this_p); // when num_addr is -1, this sets it properly.
422 assert (this_p->num_addr == 2);
423
424
425 /*
426 * Separate the addresses from the rest.
427 */
428 pinfo = strchr (stuff, ':');
429
430 if (pinfo == NULL) {
431 ax25_delete (this_p);
432 return (NULL);
433 }
434
435 *pinfo = '\0';
436 pinfo++;
437
438 /*
439 * Separate the addresses.
440 * Note that source and destination order is swappped.
441 */
442
443 /*
444 * Source address.
445 */
446
447 char *pnxt = stuff;
448 char *pa = strsep (&pnxt, ">");
449 if (pa == NULL) {
450 text_color_set(DW_COLOR_ERROR);
451 dw_printf ("Failed to create packet from text. No source address\n");
452 ax25_delete (this_p);
453 return (NULL);
454 }
455
456 if ( ! ax25_parse_addr (AX25_SOURCE, pa, strict, atemp, &ssid_temp, &heard_temp)) {
457 text_color_set(DW_COLOR_ERROR);
458 dw_printf ("Failed to create packet from text. Bad source address\n");
459 ax25_delete (this_p);
460 return (NULL);
461 }
462
463 ax25_set_addr (this_p, AX25_SOURCE, atemp);
464 ax25_set_h (this_p, AX25_SOURCE); // c/r in this position
465 ax25_set_ssid (this_p, AX25_SOURCE, ssid_temp);
466
467 /*
468 * Destination address.
469 */
470
471 pa = strsep (&pnxt, ",");
472 if (pa == NULL) {
473 text_color_set(DW_COLOR_ERROR);
474 dw_printf ("Failed to create packet from text. No destination address\n");
475 ax25_delete (this_p);
476 return (NULL);
477 }
478
479 if ( ! ax25_parse_addr (AX25_DESTINATION, pa, strict, atemp, &ssid_temp, &heard_temp)) {
480 text_color_set(DW_COLOR_ERROR);
481 dw_printf ("Failed to create packet from text. Bad destination address\n");
482 ax25_delete (this_p);
483 return (NULL);
484 }
485
486 ax25_set_addr (this_p, AX25_DESTINATION, atemp);
487 ax25_set_h (this_p, AX25_DESTINATION); // c/r in this position
488 ax25_set_ssid (this_p, AX25_DESTINATION, ssid_temp);
489
490 /*
491 * VIA path.
492 */
493
494 // Originally this used strtok_r.
495 // strtok considers all adjacent delimiters to be a single delimiter.
496 // This is handy for varying amounts of whitespace.
497 // It will never return a zero length string.
498 // All was good until this bizarre case came along:
499
500 // AISAT-1>CQ,,::CQ-0 :From AMSAT INDIA & Exseed Space |114304|48|45|42{962
501
502 // Apparently there are two digipeater fields but they are empty.
503 // When we parsed this text representation, the extra commas were ignored rather
504 // than pointed out as being invalid.
505
506 // Use strsep instead. This does not collapse adjacent delimiters.
507
508 while (( pa = strsep (&pnxt, ",")) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
509
510 int k = this_p->num_addr;
511
512 // printf ("DEBUG: get digi loop, num addr = %d, address = '%s'\n", k, pa);// FIXME
513
514 if ( ! ax25_parse_addr (k, pa, strict, atemp, &ssid_temp, &heard_temp)) {
515 text_color_set(DW_COLOR_ERROR);
516 dw_printf ("Failed to create packet from text. Bad digipeater address\n");
517 ax25_delete (this_p);
518 return (NULL);
519 }
520
521 ax25_set_addr (this_p, k, atemp);
522 ax25_set_ssid (this_p, k, ssid_temp);
523
524 // Does it have an "*" at the end?
525 // TODO: Complain if more than one "*".
526 // Could also check for all has been repeated bits are adjacent.
527
528 if (heard_temp) {
529 for ( ; k >= AX25_REPEATER_1; k--) {
530 ax25_set_h (this_p, k);
531 }
532 }
533 }
534
535
536 /*
537 * Finally, process the information part.
538 *
539 * Translate hexadecimal values like <0xff> to single bytes.
540 * MIC-E format uses 5 different non-printing characters.
541 * We might want to manually generate UTF-8 characters such as degree.
542 */
543
544 //#define DEBUG14H 1
545
546 #if DEBUG14H
547 text_color_set(DW_COLOR_DEBUG);
548 dw_printf ("BEFORE: %s\nSAFE: ", pinfo);
549 ax25_safe_print (pinfo, -1, 0);
550 dw_printf ("\n");
551 #endif
552
553 info_len = 0;
554 while (*pinfo != '\0' && info_len < AX25_MAX_INFO_LEN) {
555
556 if (strlen(pinfo) >= 6 &&
557 pinfo[0] == '<' &&
558 pinfo[1] == '0' &&
559 pinfo[2] == 'x' &&
560 isxdigit(pinfo[3]) &&
561 isxdigit(pinfo[4]) &&
562 pinfo[5] == '>') {
563
564 char *p;
565
566 info_part[info_len] = strtol (pinfo + 3, &p, 16);
567 info_len++;
568 pinfo += 6;
569 }
570 else {
571 info_part[info_len] = *pinfo;
572 info_len++;
573 pinfo++;
574 }
575 }
576 info_part[info_len] = '\0';
577
578 #if DEBUG14H
579 text_color_set(DW_COLOR_DEBUG);
580 dw_printf ("AFTER: %s\nSAFE: ", info_part);
581 ax25_safe_print (info_part, info_len, 0);
582 dw_printf ("\n");
583 #endif
584
585 /*
586 * Append the info part.
587 */
588 memcpy ((char*)(this_p->frame_data+this_p->frame_len), info_part, info_len);
589 this_p->frame_len += info_len;
590
591 return (this_p);
592 }
593
594
595 /*------------------------------------------------------------------------------
596 *
597 * Name: ax25_from_frame
598 *
599 * Purpose: Split apart an HDLC frame to components.
600 *
601 * Inputs: fbuf - Pointer to beginning of frame.
602 *
603 * flen - Length excluding the two FCS bytes.
604 *
605 * alevel - Audio level of received signal.
606 * Maximum range 0 - 100.
607 * -1 might be used when not applicable.
608 *
609 * Returns: Pointer to new packet object or NULL if error.
610 *
611 * Outputs: Use the "get" functions to retrieve information in different ways.
612 *
613 *------------------------------------------------------------------------------*/
614
615 #if AX25MEMDEBUG
ax25_from_frame_debug(unsigned char * fbuf,int flen,alevel_t alevel,char * src_file,int src_line)616 packet_t ax25_from_frame_debug (unsigned char *fbuf, int flen, alevel_t alevel, char *src_file, int src_line)
617 #else
618 packet_t ax25_from_frame (unsigned char *fbuf, int flen, alevel_t alevel)
619 #endif
620 {
621 packet_t this_p;
622
623
624 /*
625 * First make sure we have an acceptable length:
626 *
627 * We are not concerned with the FCS (CRC) because someone else checked it.
628 *
629 * Is is possible to have zero length for info?
630 *
631 * In the original version, assuming APRS, the answer was no.
632 * We always had at least 3 octets after the address part:
633 * control, protocol, and first byte of info part for data type.
634 *
635 * In later versions, this restriction was relaxed so other
636 * variations of AX.25 could be used. Now the minimum length
637 * is 7+7 for addresses plus 1 for control.
638 *
639 */
640
641
642 if (flen < AX25_MIN_PACKET_LEN || flen > AX25_MAX_PACKET_LEN)
643 {
644 text_color_set(DW_COLOR_ERROR);
645 dw_printf ("Frame length %d not in allowable range of %d to %d.\n", flen, AX25_MIN_PACKET_LEN, AX25_MAX_PACKET_LEN);
646 return (NULL);
647 }
648
649 this_p = ax25_new ();
650
651 #if AX25MEMDEBUG
652 if (ax25memdebug) {
653 text_color_set(DW_COLOR_DEBUG);
654 dw_printf ("ax25_from_frame, seq=%d, called from %s %d\n", this_p->seq, src_file, src_line);
655 }
656 #endif
657
658 /* Copy the whole thing intact. */
659
660 memcpy (this_p->frame_data, fbuf, flen);
661 this_p->frame_data[flen] = 0;
662 this_p->frame_len = flen;
663
664 /* Find number of addresses. */
665
666 this_p->num_addr = (-1);
667 (void) ax25_get_num_addr (this_p);
668
669 return (this_p);
670 }
671
672
673 /*------------------------------------------------------------------------------
674 *
675 * Name: ax25_dup
676 *
677 * Purpose: Make a copy of given packet object.
678 *
679 * Inputs: copy_from - Existing packet object.
680 *
681 * Returns: Pointer to new packet object or NULL if error.
682 *
683 *
684 *------------------------------------------------------------------------------*/
685
686
687 #if AX25MEMDEBUG
ax25_dup_debug(packet_t copy_from,char * src_file,int src_line)688 packet_t ax25_dup_debug (packet_t copy_from, char *src_file, int src_line)
689 #else
690 packet_t ax25_dup (packet_t copy_from)
691 #endif
692 {
693 int save_seq;
694 packet_t this_p;
695
696
697 this_p = ax25_new ();
698 assert (this_p != NULL);
699
700 save_seq = this_p->seq;
701
702 memcpy (this_p, copy_from, sizeof (struct packet_s));
703 this_p->seq = save_seq;
704
705 #if AX25MEMDEBUG
706 if (ax25memdebug) {
707 text_color_set(DW_COLOR_DEBUG);
708 dw_printf ("ax25_dup, seq=%d, called from %s %d, clone of seq %d\n", this_p->seq, src_file, src_line, copy_from->seq);
709 }
710 #endif
711
712 return (this_p);
713
714 }
715
716
717 /*------------------------------------------------------------------------------
718 *
719 * Name: ax25_parse_addr
720 *
721 * Purpose: Parse address with optional ssid.
722 *
723 * Inputs: position - AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER_1...
724 * Used for more specific error message. -1 if not used.
725 *
726 * in_addr - Input such as "WB2OSZ-15*"
727 *
728 * strict - 1 (true) for strict checking (6 characters, no lower case,
729 * SSID must be in range of 0 to 15).
730 * Strict is appropriate for packets sent
731 * over the radio. Communication with IGate
732 * allows lower case (e.g. "qAR") and two
733 * alphanumeric characters for the SSID.
734 * We also get messages like this from a server.
735 * KB1POR>APU25N,TCPIP*,qAC,T2NUENGLD:...
736 *
737 * 2 (extra true) will complain if * is found at end.
738 *
739 * Outputs: out_addr - Address without any SSID.
740 * Must be at least AX25_MAX_ADDR_LEN bytes.
741 *
742 * out_ssid - Numeric value of SSID.
743 *
744 * out_heard - True if "*" found.
745 *
746 * Returns: True (1) if OK, false (0) if any error.
747 * When 0, out_addr, out_ssid, and out_heard are undefined.
748 *
749 *
750 *------------------------------------------------------------------------------*/
751
752 static const char *position_name[1 + AX25_MAX_ADDRS] = {
753 "", "Destination ", "Source ",
754 "Digi1 ", "Digi2 ", "Digi3 ", "Digi4 ",
755 "Digi5 ", "Digi6 ", "Digi7 ", "Digi8 " };
756
ax25_parse_addr(int position,char * in_addr,int strict,char * out_addr,int * out_ssid,int * out_heard)757 int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard)
758 {
759 char *p;
760 char sstr[8]; /* Should be 1 or 2 digits for SSID. */
761 int i, j, k;
762 int maxlen;
763
764 *out_addr = '\0';
765 *out_ssid = 0;
766 *out_heard = 0;
767
768 // dw_printf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict);
769
770 if (position < -1) position = -1;
771 if (position > AX25_REPEATER_8) position = AX25_REPEATER_8;
772 position++; /* Adjust for position_name above. */
773
774 if (strlen(in_addr) == 0) {
775 text_color_set(DW_COLOR_ERROR);
776 dw_printf ("%sAddress \"%s\" is empty.\n", position_name[position], in_addr);
777 return 0;
778 }
779
780 if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) {
781
782 text_color_set(DW_COLOR_ERROR);
783 dw_printf ("%sAddress \"%s\" is a \"q-construct\" used for communicating with\n", position_name[position], in_addr);
784 dw_printf ("APRS Internet Servers. It should never appear when going over the radio.\n");
785 }
786
787 // dw_printf ("ax25_parse_addr in: %s\n", in_addr);
788
789 maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN-1);
790 p = in_addr;
791 i = 0;
792 for (p = in_addr; *p != '\0' && *p != '-' && *p != '*'; p++) {
793 if (i >= maxlen) {
794 text_color_set(DW_COLOR_ERROR);
795 dw_printf ("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen);
796 return 0;
797 }
798 if ( ! isalnum(*p)) {
799 text_color_set(DW_COLOR_ERROR);
800 dw_printf ("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p-in_addr)+1);
801 return 0;
802 }
803
804 out_addr[i++] = *p;
805 out_addr[i] = '\0';
806
807 #if DECAMAIN // Hack when running in decode_aprs utility.
808 // Exempt the "qA..." case because it was already mentioned.
809
810 if (strict && islower(*p) && strncmp(in_addr, "qA", 2) != 0) {
811 text_color_set(DW_COLOR_ERROR);
812 dw_printf ("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr);
813 }
814 #else
815 if (strict && islower(*p)) {
816 text_color_set(DW_COLOR_ERROR);
817 dw_printf ("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr);
818 return 0;
819 }
820 #endif
821 }
822
823 j = 0;
824 sstr[j] = '\0';
825 if (*p == '-') {
826 for (p++; isalnum(*p); p++) {
827 if (j >= 2) {
828 text_color_set(DW_COLOR_ERROR);
829 dw_printf ("%sSSID is too long. SSID part of \"%s\" has more than 2 characters.\n", position_name[position], in_addr);
830 return 0;
831 }
832 sstr[j++] = *p;
833 sstr[j] = '\0';
834 if (strict && ! isdigit(*p)) {
835 text_color_set(DW_COLOR_ERROR);
836 dw_printf ("%sSSID must be digits. \"%s\" has letters in SSID.\n", position_name[position], in_addr);
837 return 0;
838 }
839 }
840 k = atoi(sstr);
841 if (k < 0 || k > 15) {
842 text_color_set(DW_COLOR_ERROR);
843 dw_printf ("%sSSID out of range. SSID of \"%s\" not in range of 0 to 15.\n", position_name[position], in_addr);
844 return 0;
845 }
846 *out_ssid = k;
847 }
848
849 if (*p == '*') {
850 *out_heard = 1;
851 p++;
852 if (strict == 2) {
853 text_color_set(DW_COLOR_ERROR);
854 dw_printf ("\"*\" is not allowed at end of address \"%s\" here.\n", in_addr);
855 return 0;
856 }
857 }
858
859 if (*p != '\0') {
860 text_color_set(DW_COLOR_ERROR);
861 dw_printf ("Invalid character \"%c\" found in %saddress \"%s\".\n", *p, position_name[position], in_addr);
862 return 0;
863 }
864
865 // dw_printf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard);
866
867 return (1);
868
869 } /* end ax25_parse_addr */
870
871
872 /*-------------------------------------------------------------------
873 *
874 * Name: ax25_check_addresses
875 *
876 * Purpose: Check addresses of given packet and print message if any issues.
877 * We call this when receiving and transmitting.
878 *
879 * Inputs: pp - packet object pointer.
880 *
881 * Errors: Print error message.
882 *
883 * Returns: 1 for all valid. 0 if not.
884 *
885 * Examples: I was surprised to get this from an APRS-IS server with
886 * a lower case source address.
887 *
888 * n1otx>APRS,TCPIP*,qAC,THIRD:@141335z4227.48N/07111.73W_348/005g014t044r000p000h60b10075.wview_5_20_2
889 *
890 * I haven't gotten to the bottom of this yet but it sounds
891 * like "q constructs" are somehow getting on to the air when
892 * they should only appear in conversations with IGate servers.
893 *
894 * https://groups.yahoo.com/neo/groups/direwolf_packet/conversations/topics/678
895 *
896 * WB0VGI-7>APDW12,W0YC-5*,qAR,AE0RF-10:}N0DZQ-10>APWW10,TCPIP,WB0VGI-7*:;145.230MN*080306z4607.62N/09230.58WrKE0ACL/R 145.230- T146.2 (Pine County ARES)
897 *
898 * Typical result:
899 *
900 * Digipeater WIDE2 (probably N3LEE-4) audio level = 28(10/6) [NONE] __|||||||
901 * [0.5] VE2DJE-9>P_0_P?,VE2PCQ-3,K1DF-7,N3LEE-4,WIDE2*:'{S+l <0x1c>>/
902 * Invalid character "_" in MIC-E destination/latitude.
903 * Invalid character "_" in MIC-E destination/latitude.
904 * Invalid character "?" in MIC-E destination/latitude.
905 * Invalid MIC-E N/S encoding in 4th character of destination.
906 * Invalid MIC-E E/W encoding in 6th character of destination.
907 * MIC-E, normal car (side view), Unknown manufacturer, Returning
908 * N 00 00.0000, E 005 55.1500, 0 MPH
909 * Invalid character "_" found in Destination address "P_0_P?".
910 *
911 * *** The origin and journey of this packet should receive some scrutiny. ***
912 *
913 *--------------------------------------------------------------------*/
914
ax25_check_addresses(packet_t pp)915 int ax25_check_addresses (packet_t pp)
916 {
917 int n;
918 char addr[AX25_MAX_ADDR_LEN];
919 char ignore1[AX25_MAX_ADDR_LEN];
920 int ignore2, ignore3;
921 int all_ok = 1;
922
923 for (n = 0; n < ax25_get_num_addr(pp); n++) {
924 ax25_get_addr_with_ssid (pp, n, addr);
925 all_ok &= ax25_parse_addr (n, addr, 1, ignore1, &ignore2, &ignore3);
926 }
927
928 if (! all_ok) {
929 text_color_set(DW_COLOR_ERROR);
930 dw_printf ("\n");
931 dw_printf ("*** The origin and journey of this packet should receive some scrutiny. ***\n");
932 dw_printf ("\n");
933 }
934
935 return (all_ok);
936 } /* end ax25_check_addresses */
937
938
939 /*------------------------------------------------------------------------------
940 *
941 * Name: ax25_unwrap_third_party
942 *
943 * Purpose: Unwrap a third party messge from the header.
944 *
945 * Inputs: copy_from - Existing packet object.
946 *
947 * Returns: Pointer to new packet object or NULL if error.
948 *
949 * Example: Input: A>B,C:}D>E,F:info
950 * Output: D>E,F:info
951 *
952 *------------------------------------------------------------------------------*/
953
ax25_unwrap_third_party(packet_t from_pp)954 packet_t ax25_unwrap_third_party (packet_t from_pp)
955 {
956 unsigned char *info_p;
957 packet_t result_pp;
958
959 if (ax25_get_dti(from_pp) != '}') {
960 text_color_set(DW_COLOR_ERROR);
961 dw_printf ("Internal error: ax25_unwrap_third_party: wrong data type.\n");
962 return (NULL);
963 }
964
965 (void) ax25_get_info (from_pp, &info_p);
966
967 // Want strict because addresses should conform to AX.25 here.
968 // That's not the case for something from an Internet Server.
969
970 result_pp = ax25_from_text((char *)info_p + 1, 1);
971
972 return (result_pp);
973 }
974
975
976
977 /*------------------------------------------------------------------------------
978 *
979 * Name: ax25_set_addr
980 *
981 * Purpose: Add or change an address.
982 *
983 * Inputs: n - Index of address. Use the symbols
984 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
985 *
986 * Must be either an existing address or one greater
987 * than the final which causes a new one to be added.
988 *
989 * ad - Address with optional dash and substation id.
990 *
991 * Assumption: ax25_from_text or ax25_from_frame was called first.
992 *
993 * TODO: ax25_from_text could use this.
994 *
995 * Returns: None.
996 *
997 *------------------------------------------------------------------------------*/
998
ax25_set_addr(packet_t this_p,int n,char * ad)999 void ax25_set_addr (packet_t this_p, int n, char *ad)
1000 {
1001 int ssid_temp, heard_temp;
1002 char atemp[AX25_MAX_ADDR_LEN];
1003 int i;
1004
1005 assert (this_p->magic1 == MAGIC);
1006 assert (this_p->magic2 == MAGIC);
1007 assert (n >= 0 && n < AX25_MAX_ADDRS);
1008
1009 //dw_printf ("ax25_set_addr (%d, %s) num_addr=%d\n", n, ad, this_p->num_addr);
1010
1011 if (strlen(ad) == 0) {
1012 text_color_set(DW_COLOR_ERROR);
1013 dw_printf ("Set address error! Station address for position %d is empty!\n", n);
1014 }
1015
1016 if (n >= 0 && n < this_p->num_addr) {
1017
1018 //dw_printf ("ax25_set_addr , existing case\n");
1019 /*
1020 * Set existing address position.
1021 */
1022
1023 // Why aren't we setting 'strict' here?
1024 // Messages from IGate have q-constructs.
1025 // We use this to parse it and later remove unwanted parts.
1026
1027 ax25_parse_addr (n, ad, 0, atemp, &ssid_temp, &heard_temp);
1028
1029 memset (this_p->frame_data + n*7, ' ' << 1, 6);
1030
1031 for (i=0; i<6 && atemp[i] != '\0'; i++) {
1032 this_p->frame_data[n*7+i] = atemp[i] << 1;
1033 }
1034 ax25_set_ssid (this_p, n, ssid_temp);
1035 }
1036 else if (n == this_p->num_addr) {
1037
1038 //dw_printf ("ax25_set_addr , appending case\n");
1039 /*
1040 * One beyond last position, process as insert.
1041 */
1042
1043 ax25_insert_addr (this_p, n, ad);
1044 }
1045 else {
1046 text_color_set(DW_COLOR_ERROR);
1047 dw_printf ("Internal error, ax25_set_addr, bad position %d for '%s'\n", n, ad);
1048 }
1049
1050 //dw_printf ("------\n");
1051 //dw_printf ("dump after ax25_set_addr (%d, %s)\n", n, ad);
1052 //ax25_hex_dump (this_p);
1053 //dw_printf ("------\n");
1054 }
1055
1056
1057 /*------------------------------------------------------------------------------
1058 *
1059 * Name: ax25_insert_addr
1060 *
1061 * Purpose: Insert address at specified position, shifting others up one
1062 * position.
1063 * This is used when a digipeater wants to insert its own call
1064 * for tracing purposes.
1065 * For example:
1066 * W1ABC>TEST,WIDE3-3
1067 * Would become:
1068 * W1ABC>TEST,WB2OSZ-1*,WIDE3-2
1069 *
1070 * Inputs: n - Index of address. Use the symbols
1071 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1072 *
1073 * ad - Address with optional dash and substation id.
1074 *
1075 * Bugs: Little validity or bounds checking is performed. Be careful.
1076 *
1077 * Assumption: ax25_from_text or ax25_from_frame was called first.
1078 *
1079 * Returns: None.
1080 *
1081 *
1082 *------------------------------------------------------------------------------*/
1083
ax25_insert_addr(packet_t this_p,int n,char * ad)1084 void ax25_insert_addr (packet_t this_p, int n, char *ad)
1085 {
1086 int ssid_temp, heard_temp;
1087 char atemp[AX25_MAX_ADDR_LEN];
1088 int i;
1089 int expect;
1090
1091 assert (this_p->magic1 == MAGIC);
1092 assert (this_p->magic2 == MAGIC);
1093 assert (n >= AX25_REPEATER_1 && n < AX25_MAX_ADDRS);
1094
1095 //dw_printf ("ax25_insert_addr (%d, %s)\n", n, ad);
1096
1097 if (strlen(ad) == 0) {
1098 text_color_set(DW_COLOR_ERROR);
1099 dw_printf ("Set address error! Station address for position %d is empty!\n", n);
1100 }
1101
1102 /* Don't do it if we already have the maximum number. */
1103 /* Should probably return success/fail code but currently the caller doesn't care. */
1104
1105 if ( this_p->num_addr >= AX25_MAX_ADDRS) {
1106 return;
1107 }
1108
1109 CLEAR_LAST_ADDR_FLAG;
1110
1111 this_p->num_addr++;
1112
1113 memmove (this_p->frame_data + (n+1)*7, this_p->frame_data + n*7, this_p->frame_len - (n*7));
1114 memset (this_p->frame_data + n*7, ' ' << 1, 6);
1115 this_p->frame_len += 7;
1116 this_p->frame_data[n*7+6] = SSID_RR_MASK;
1117
1118 SET_LAST_ADDR_FLAG;
1119
1120 // Why aren't we setting 'strict' here?
1121 // Messages from IGate have q-constructs.
1122 // We use this to parse it and later remove unwanted parts.
1123
1124 ax25_parse_addr (n, ad, 0, atemp, &ssid_temp, &heard_temp);
1125 memset (this_p->frame_data + n*7, ' ' << 1, 6);
1126 for (i=0; i<6 && atemp[i] != '\0'; i++) {
1127 this_p->frame_data[n*7+i] = atemp[i] << 1;
1128 }
1129
1130 ax25_set_ssid (this_p, n, ssid_temp);
1131
1132 // Sanity check after messing with number of addresses.
1133
1134 expect = this_p->num_addr;
1135 this_p->num_addr = (-1);
1136 if (expect != ax25_get_num_addr (this_p)) {
1137 text_color_set(DW_COLOR_ERROR);
1138 dw_printf ("Internal error ax25_remove_addr expect %d, actual %d\n", expect, this_p->num_addr);
1139 }
1140 }
1141
1142
1143 /*------------------------------------------------------------------------------
1144 *
1145 * Name: ax25_remove_addr
1146 *
1147 * Purpose: Remove address at specified position, shifting others down one position.
1148 * This is used when we want to remove something from the digipeater list.
1149 *
1150 * Inputs: n - Index of address. Use the symbols
1151 * AX25_REPEATER1, AX25_REPEATER2, etc.
1152 *
1153 * Bugs: Little validity or bounds checking is performed. Be careful.
1154 *
1155 * Assumption: ax25_from_text or ax25_from_frame was called first.
1156 *
1157 * Returns: None.
1158 *
1159 *
1160 *------------------------------------------------------------------------------*/
1161
ax25_remove_addr(packet_t this_p,int n)1162 void ax25_remove_addr (packet_t this_p, int n)
1163 {
1164 int expect;
1165
1166 assert (this_p->magic1 == MAGIC);
1167 assert (this_p->magic2 == MAGIC);
1168 assert (n >= AX25_REPEATER_1 && n < AX25_MAX_ADDRS);
1169
1170 /* Shift those beyond to fill this position. */
1171
1172 CLEAR_LAST_ADDR_FLAG;
1173
1174 this_p->num_addr--;
1175
1176 memmove (this_p->frame_data + n*7, this_p->frame_data + (n+1)*7, this_p->frame_len - ((n+1)*7));
1177 this_p->frame_len -= 7;
1178 SET_LAST_ADDR_FLAG;
1179
1180 // Sanity check after messing with number of addresses.
1181
1182 expect = this_p->num_addr;
1183 this_p->num_addr = (-1);
1184 if (expect != ax25_get_num_addr (this_p)) {
1185 text_color_set(DW_COLOR_ERROR);
1186 dw_printf ("Internal error ax25_remove_addr expect %d, actual %d\n", expect, this_p->num_addr);
1187 }
1188
1189 }
1190
1191
1192 /*------------------------------------------------------------------------------
1193 *
1194 * Name: ax25_get_num_addr
1195 *
1196 * Purpose: Return number of addresses in current packet.
1197 *
1198 * Assumption: ax25_from_text or ax25_from_frame was called first.
1199 *
1200 * Returns: Number of addresses in the current packet.
1201 * Should be in the range of 2 .. AX25_MAX_ADDRS.
1202 *
1203 * Version 0.9: Could be zero for a non AX.25 frame in KISS mode.
1204 *
1205 *------------------------------------------------------------------------------*/
1206
ax25_get_num_addr(packet_t this_p)1207 int ax25_get_num_addr (packet_t this_p)
1208 {
1209 //unsigned char *pf;
1210 int a;
1211 int addr_bytes;
1212
1213
1214 assert (this_p->magic1 == MAGIC);
1215 assert (this_p->magic2 == MAGIC);
1216
1217 /* Use cached value if already set. */
1218
1219 if (this_p->num_addr >= 0) {
1220 return (this_p->num_addr);
1221 }
1222
1223 /* Otherwise, determine the number ofaddresses. */
1224
1225 this_p->num_addr = 0; /* Number of addresses extracted. */
1226
1227 addr_bytes = 0;
1228 for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) {
1229 if (this_p->frame_data[a] & SSID_LAST_MASK) {
1230 addr_bytes = a + 1;
1231 }
1232 }
1233
1234 if (addr_bytes % 7 == 0) {
1235 int addrs = addr_bytes / 7;
1236 if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) {
1237 this_p->num_addr = addrs;
1238 }
1239 }
1240
1241 return (this_p->num_addr);
1242 }
1243
1244
1245 /*------------------------------------------------------------------------------
1246 *
1247 * Name: ax25_get_num_repeaters
1248 *
1249 * Purpose: Return number of repeater addresses in current packet.
1250 *
1251 * Assumption: ax25_from_text or ax25_from_frame was called first.
1252 *
1253 * Returns: Number of addresses in the current packet - 2.
1254 * Should be in the range of 0 .. AX25_MAX_ADDRS - 2.
1255 *
1256 *------------------------------------------------------------------------------*/
1257
ax25_get_num_repeaters(packet_t this_p)1258 int ax25_get_num_repeaters (packet_t this_p)
1259 {
1260 assert (this_p->magic1 == MAGIC);
1261 assert (this_p->magic2 == MAGIC);
1262
1263 if (this_p->num_addr >= 2) {
1264 return (this_p->num_addr - 2);
1265 }
1266
1267 return (0);
1268 }
1269
1270
1271 /*------------------------------------------------------------------------------
1272 *
1273 * Name: ax25_get_addr_with_ssid
1274 *
1275 * Purpose: Return specified address with any SSID in current packet.
1276 *
1277 * Inputs: n - Index of address. Use the symbols
1278 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1279 *
1280 * Outputs: station - String representation of the station, including the SSID.
1281 * e.g. "WB2OSZ-15"
1282 * Usually variables will be AX25_MAX_ADDR_LEN bytes
1283 * but 10 would be adequate.
1284 *
1285 * Bugs: No bounds checking is performed. Be careful.
1286 *
1287 * Assumption: ax25_from_text or ax25_from_frame was called first.
1288 *
1289 * Returns: Character string in usual human readable format,
1290 *
1291 *
1292 *------------------------------------------------------------------------------*/
1293
ax25_get_addr_with_ssid(packet_t this_p,int n,char * station)1294 void ax25_get_addr_with_ssid (packet_t this_p, int n, char *station)
1295 {
1296 int ssid;
1297 char sstr[8]; /* Should be 1 or 2 digits for SSID. */
1298 int i;
1299
1300 assert (this_p->magic1 == MAGIC);
1301 assert (this_p->magic2 == MAGIC);
1302
1303
1304 if (n < 0) {
1305 text_color_set(DW_COLOR_ERROR);
1306 dw_printf ("Internal error detected in ax25_get_addr_with_ssid, %s, line %d.\n", __FILE__, __LINE__);
1307 dw_printf ("Address index, %d, is less than zero.\n", n);
1308 strlcpy (station, "??????", 10);
1309 return;
1310 }
1311
1312 if (n >= this_p->num_addr) {
1313 text_color_set(DW_COLOR_ERROR);
1314 dw_printf ("Internal error detected in ax25_get_addr_with_ssid, %s, line %d.\n", __FILE__, __LINE__);
1315 dw_printf ("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr);
1316 strlcpy (station, "??????", 10);
1317 return;
1318 }
1319
1320 // At one time this would stop at the first space, on the assumption we would have only trailing spaces.
1321 // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space.
1322 // In that case, we would have returned a zero length string here.
1323 // Now we return exactly what is in the address field and trim trailing spaces.
1324 // This will provide better information for troubleshooting.
1325
1326 for (i=0; i<6; i++) {
1327 station[i] = (this_p->frame_data[n*7+i] >> 1) & 0x7f;
1328 }
1329 station[6] = '\0';
1330
1331 for (i=5; i>=0; i--) {
1332 if (station[i] == '\0') {
1333 text_color_set(DW_COLOR_ERROR);
1334 dw_printf ("Station address \"%s\" contains nul character. AX.25 protocol requires trailing ASCII spaces when less than 6 characters.\n", station);
1335 }
1336 else if (station[i] == ' ')
1337 station[i] = '\0';
1338 else
1339 break;
1340 }
1341
1342 if (strlen(station) == 0) {
1343 text_color_set(DW_COLOR_ERROR);
1344 dw_printf ("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n);
1345 }
1346
1347 ssid = ax25_get_ssid (this_p, n);
1348 if (ssid != 0) {
1349 snprintf (sstr, sizeof(sstr), "-%d", ssid);
1350 strlcat (station, sstr, 10);
1351 }
1352
1353 } /* end ax25_get_addr_with_ssid */
1354
1355
1356 /*------------------------------------------------------------------------------
1357 *
1358 * Name: ax25_get_addr_no_ssid
1359 *
1360 * Purpose: Return specified address WITHOUT any SSID.
1361 *
1362 * Inputs: n - Index of address. Use the symbols
1363 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1364 *
1365 * Outputs: station - String representation of the station, WITHOUT the SSID.
1366 * e.g. "WB2OSZ"
1367 * Usually variables will be AX25_MAX_ADDR_LEN bytes
1368 * but 7 would be adequate.
1369 *
1370 * Bugs: No bounds checking is performed. Be careful.
1371 *
1372 * Assumption: ax25_from_text or ax25_from_frame was called first.
1373 *
1374 * Returns: Character string in usual human readable format,
1375 *
1376 *
1377 *------------------------------------------------------------------------------*/
1378
ax25_get_addr_no_ssid(packet_t this_p,int n,char * station)1379 void ax25_get_addr_no_ssid (packet_t this_p, int n, char *station)
1380 {
1381 int i;
1382
1383 assert (this_p->magic1 == MAGIC);
1384 assert (this_p->magic2 == MAGIC);
1385
1386
1387 if (n < 0) {
1388 text_color_set(DW_COLOR_ERROR);
1389 dw_printf ("Internal error detected in ax25_get_addr_no_ssid, %s, line %d.\n", __FILE__, __LINE__);
1390 dw_printf ("Address index, %d, is less than zero.\n", n);
1391 strlcpy (station, "??????", 7);
1392 return;
1393 }
1394
1395 if (n >= this_p->num_addr) {
1396 text_color_set(DW_COLOR_ERROR);
1397 dw_printf ("Internal error detected in ax25_get_no_with_ssid, %s, line %d.\n", __FILE__, __LINE__);
1398 dw_printf ("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr);
1399 strlcpy (station, "??????", 7);
1400 return;
1401 }
1402
1403 // At one time this would stop at the first space, on the assumption we would have only trailing spaces.
1404 // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space.
1405 // In that case, we would have returned a zero length string here.
1406 // Now we return exactly what is in the address field and trim trailing spaces.
1407 // This will provide better information for troubleshooting.
1408
1409 for (i=0; i<6; i++) {
1410 station[i] = (this_p->frame_data[n*7+i] >> 1) & 0x7f;
1411 }
1412 station[6] = '\0';
1413
1414 for (i=5; i>=0; i--) {
1415 if (station[i] == ' ')
1416 station[i] = '\0';
1417 else
1418 break;
1419 }
1420
1421 if (strlen(station) == 0) {
1422 text_color_set(DW_COLOR_ERROR);
1423 dw_printf ("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n);
1424 }
1425
1426 } /* end ax25_get_addr_no_ssid */
1427
1428
1429 /*------------------------------------------------------------------------------
1430 *
1431 * Name: ax25_get_ssid
1432 *
1433 * Purpose: Return SSID of specified address in current packet.
1434 *
1435 * Inputs: n - Index of address. Use the symbols
1436 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1437 *
1438 * Assumption: ax25_from_text or ax25_from_frame was called first.
1439 *
1440 * Returns: Substation id, as integer 0 .. 15.
1441 *
1442 *------------------------------------------------------------------------------*/
1443
ax25_get_ssid(packet_t this_p,int n)1444 int ax25_get_ssid (packet_t this_p, int n)
1445 {
1446
1447 assert (this_p->magic1 == MAGIC);
1448 assert (this_p->magic2 == MAGIC);
1449
1450 if (n >= 0 && n < this_p->num_addr) {
1451 return ((this_p->frame_data[n*7+6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT);
1452 }
1453 else {
1454 text_color_set(DW_COLOR_ERROR);
1455 dw_printf ("Internal error: ax25_get_ssid(%d), num_addr=%d\n", n, this_p->num_addr);
1456 return (0);
1457 }
1458 }
1459
1460
1461 /*------------------------------------------------------------------------------
1462 *
1463 * Name: ax25_set_ssid
1464 *
1465 * Purpose: Set the SSID of specified address in current packet.
1466 *
1467 * Inputs: n - Index of address. Use the symbols
1468 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1469 *
1470 * ssid - New SSID. Must be in range of 0 to 15.
1471 *
1472 * Assumption: ax25_from_text or ax25_from_frame was called first.
1473 *
1474 * Bugs: Rewrite to keep call and SSID separate internally.
1475 *
1476 *------------------------------------------------------------------------------*/
1477
ax25_set_ssid(packet_t this_p,int n,int ssid)1478 void ax25_set_ssid (packet_t this_p, int n, int ssid)
1479 {
1480
1481 assert (this_p->magic1 == MAGIC);
1482 assert (this_p->magic2 == MAGIC);
1483
1484
1485 if (n >= 0 && n < this_p->num_addr) {
1486 this_p->frame_data[n*7+6] = (this_p->frame_data[n*7+6] & ~ SSID_SSID_MASK) |
1487 ((ssid << SSID_SSID_SHIFT) & SSID_SSID_MASK) ;
1488 }
1489 else {
1490 text_color_set(DW_COLOR_ERROR);
1491 dw_printf ("Internal error: ax25_set_ssid(%d,%d), num_addr=%d\n", n, ssid, this_p->num_addr);
1492 }
1493 }
1494
1495
1496 /*------------------------------------------------------------------------------
1497 *
1498 * Name: ax25_get_h
1499 *
1500 * Purpose: Return "has been repeated" flag of specified address in current packet.
1501 *
1502 * Inputs: n - Index of address. Use the symbols
1503 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1504 *
1505 * Bugs: No bounds checking is performed. Be careful.
1506 *
1507 * Assumption: ax25_from_text or ax25_from_frame was called first.
1508 *
1509 * Returns: True or false.
1510 *
1511 *------------------------------------------------------------------------------*/
1512
ax25_get_h(packet_t this_p,int n)1513 int ax25_get_h (packet_t this_p, int n)
1514 {
1515
1516 assert (this_p->magic1 == MAGIC);
1517 assert (this_p->magic2 == MAGIC);
1518 assert (n >= 0 && n < this_p->num_addr);
1519
1520 if (n >= 0 && n < this_p->num_addr) {
1521 return ((this_p->frame_data[n*7+6] & SSID_H_MASK) >> SSID_H_SHIFT);
1522 }
1523 else {
1524 text_color_set(DW_COLOR_ERROR);
1525 dw_printf ("Internal error: ax25_get_h(%d), num_addr=%d\n", n, this_p->num_addr);
1526 return (0);
1527 }
1528 }
1529
1530
1531 /*------------------------------------------------------------------------------
1532 *
1533 * Name: ax25_set_h
1534 *
1535 * Purpose: Set the "has been repeated" flag of specified address in current packet.
1536 *
1537 * Inputs: n - Index of address. Use the symbols
1538 * Should be in range of AX25_REPEATER_1 .. AX25_REPEATER_8.
1539 *
1540 * Bugs: No bounds checking is performed. Be careful.
1541 *
1542 * Assumption: ax25_from_text or ax25_from_frame was called first.
1543 *
1544 * Returns: None
1545 *
1546 *------------------------------------------------------------------------------*/
1547
ax25_set_h(packet_t this_p,int n)1548 void ax25_set_h (packet_t this_p, int n)
1549 {
1550
1551 assert (this_p->magic1 == MAGIC);
1552 assert (this_p->magic2 == MAGIC);
1553
1554 if (n >= 0 && n < this_p->num_addr) {
1555 this_p->frame_data[n*7+6] |= SSID_H_MASK;
1556 }
1557 else {
1558 text_color_set(DW_COLOR_ERROR);
1559 dw_printf ("Internal error: ax25_set_hd(%d), num_addr=%d\n", n, this_p->num_addr);
1560 }
1561 }
1562
1563
1564 /*------------------------------------------------------------------------------
1565 *
1566 * Name: ax25_get_heard
1567 *
1568 * Purpose: Return index of the station that we heard.
1569 *
1570 * Inputs: none
1571 *
1572 *
1573 * Assumption: ax25_from_text or ax25_from_frame was called first.
1574 *
1575 * Returns: If any of the digipeaters have the has-been-repeated bit set,
1576 * return the index of the last one. Otherwise return index for source.
1577 *
1578 *------------------------------------------------------------------------------*/
1579
ax25_get_heard(packet_t this_p)1580 int ax25_get_heard(packet_t this_p)
1581 {
1582 int i;
1583 int result;
1584
1585 assert (this_p->magic1 == MAGIC);
1586 assert (this_p->magic2 == MAGIC);
1587
1588 result = AX25_SOURCE;
1589
1590 for (i = AX25_REPEATER_1; i < ax25_get_num_addr(this_p); i++) {
1591
1592 if (ax25_get_h(this_p,i)) {
1593 result = i;
1594 }
1595 }
1596 return (result);
1597 }
1598
1599
1600
1601 /*------------------------------------------------------------------------------
1602 *
1603 * Name: ax25_get_first_not_repeated
1604 *
1605 * Purpose: Return index of the first repeater that does NOT have the
1606 * "has been repeated" flag set or -1 if none.
1607 *
1608 * Inputs: none
1609 *
1610 *
1611 * Assumption: ax25_from_text or ax25_from_frame was called first.
1612 *
1613 * Returns: In range of X25_REPEATER_1 .. X25_REPEATER_8 or -1 if none.
1614 *
1615 *------------------------------------------------------------------------------*/
1616
ax25_get_first_not_repeated(packet_t this_p)1617 int ax25_get_first_not_repeated(packet_t this_p)
1618 {
1619 int i;
1620
1621 assert (this_p->magic1 == MAGIC);
1622 assert (this_p->magic2 == MAGIC);
1623
1624 for (i = AX25_REPEATER_1; i < ax25_get_num_addr(this_p); i++) {
1625
1626 if ( ! ax25_get_h(this_p,i)) {
1627 return (i);
1628 }
1629 }
1630 return (-1);
1631 }
1632
1633
1634 /*------------------------------------------------------------------------------
1635 *
1636 * Name: ax25_get_rr
1637 *
1638 * Purpose: Return the two reserved "RR" bits in the specified address field.
1639 *
1640 * Inputs: pp - Packet object.
1641 *
1642 * n - Index of address. Use the symbols
1643 * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
1644 *
1645 * Returns: 0, 1, 2, or 3.
1646 *
1647 *------------------------------------------------------------------------------*/
1648
ax25_get_rr(packet_t this_p,int n)1649 int ax25_get_rr (packet_t this_p, int n)
1650 {
1651
1652 assert (this_p->magic1 == MAGIC);
1653 assert (this_p->magic2 == MAGIC);
1654 assert (n >= 0 && n < this_p->num_addr);
1655
1656 if (n >= 0 && n < this_p->num_addr) {
1657 return ((this_p->frame_data[n*7+6] & SSID_RR_MASK) >> SSID_RR_SHIFT);
1658 }
1659 else {
1660 text_color_set(DW_COLOR_ERROR);
1661 dw_printf ("Internal error: ax25_get_rr(%d), num_addr=%d\n", n, this_p->num_addr);
1662 return (0);
1663 }
1664 }
1665
1666
1667 /*------------------------------------------------------------------------------
1668 *
1669 * Name: ax25_get_info
1670 *
1671 * Purpose: Obtain Information part of current packet.
1672 *
1673 * Inputs: this_p - Packet object pointer.
1674 *
1675 * Outputs: paddr - Starting address of information part is returned here.
1676 *
1677 * Assumption: ax25_from_text or ax25_from_frame was called first.
1678 *
1679 * Returns: Number of octets in the Information part.
1680 * Should be in the range of AX25_MIN_INFO_LEN .. AX25_MAX_INFO_LEN.
1681 *
1682 *------------------------------------------------------------------------------*/
1683
ax25_get_info(packet_t this_p,unsigned char ** paddr)1684 int ax25_get_info (packet_t this_p, unsigned char **paddr)
1685 {
1686 unsigned char *info_ptr;
1687 int info_len;
1688
1689
1690 assert (this_p->magic1 == MAGIC);
1691 assert (this_p->magic2 == MAGIC);
1692
1693 if (this_p->num_addr >= 2) {
1694
1695 /* AX.25 */
1696
1697 info_ptr = this_p->frame_data + ax25_get_info_offset(this_p);
1698 info_len = ax25_get_num_info(this_p);
1699 }
1700 else {
1701
1702 /* Not AX.25. Treat Whole packet as info. */
1703
1704 info_ptr = this_p->frame_data;
1705 info_len = this_p->frame_len;
1706 }
1707
1708 /* Add nul character in case caller treats as printable string. */
1709
1710 assert (info_len >= 0);
1711
1712 info_ptr[info_len] = '\0';
1713
1714 *paddr = info_ptr;
1715 return (info_len);
1716
1717 } /* end ax25_get_info */
1718
1719
1720 /*------------------------------------------------------------------------------
1721 *
1722 * Name: ax25_cut_at_crlf
1723 *
1724 * Purpose: Truncate the information part at the first CR or LF.
1725 * This is used for the RF>IS IGate function.
1726 * CR/LF is used as record separator so we must remove it
1727 * before packaging up packet to sending to server.
1728 *
1729 * Inputs: this_p - Packet object pointer.
1730 *
1731 * Outputs: Packet is modified in place.
1732 *
1733 * Returns: Number of characters removed from the end.
1734 * 0 if not changed.
1735 *
1736 * Assumption: ax25_from_text or ax25_from_frame was called first.
1737 *
1738 *------------------------------------------------------------------------------*/
1739
ax25_cut_at_crlf(packet_t this_p)1740 int ax25_cut_at_crlf (packet_t this_p)
1741 {
1742 unsigned char *info_ptr;
1743 int info_len;
1744 int j;
1745
1746
1747 assert (this_p->magic1 == MAGIC);
1748 assert (this_p->magic2 == MAGIC);
1749
1750 info_len = ax25_get_info (this_p, &info_ptr);
1751
1752 // Can't use strchr because there is potential of nul character.
1753
1754 for (j = 0; j < info_len; j++) {
1755
1756 if (info_ptr[j] == '\r' || info_ptr[j] == '\n') {
1757
1758 int chop = info_len - j;
1759
1760 this_p->frame_len -= chop;
1761 return (chop);
1762 }
1763 }
1764
1765 return (0);
1766 }
1767
1768
1769 /*------------------------------------------------------------------------------
1770 *
1771 * Name: ax25_get_dti
1772 *
1773 * Purpose: Get Data Type Identifier from Information part.
1774 *
1775 * Inputs: None.
1776 *
1777 * Assumption: ax25_from_text or ax25_from_frame was called first.
1778 *
1779 * Returns: First byte from the information part.
1780 *
1781 *------------------------------------------------------------------------------*/
1782
ax25_get_dti(packet_t this_p)1783 int ax25_get_dti (packet_t this_p)
1784 {
1785 assert (this_p->magic1 == MAGIC);
1786 assert (this_p->magic2 == MAGIC);
1787
1788 if (this_p->num_addr >= 2) {
1789 return (this_p->frame_data[ax25_get_info_offset(this_p)]);
1790 }
1791 return (' ');
1792 }
1793
1794 /*------------------------------------------------------------------------------
1795 *
1796 * Name: ax25_set_nextp
1797 *
1798 * Purpose: Set next packet object in queue.
1799 *
1800 * Inputs: this_p - Current packet object.
1801 *
1802 * next_p - pointer to next one
1803 *
1804 * Description: This is used to build a linked list for a queue.
1805 *
1806 *------------------------------------------------------------------------------*/
1807
ax25_set_nextp(packet_t this_p,packet_t next_p)1808 void ax25_set_nextp (packet_t this_p, packet_t next_p)
1809 {
1810 assert (this_p->magic1 == MAGIC);
1811 assert (this_p->magic2 == MAGIC);
1812
1813 this_p->nextp = next_p;
1814 }
1815
1816
1817
1818 /*------------------------------------------------------------------------------
1819 *
1820 * Name: ax25_get_nextp
1821 *
1822 * Purpose: Obtain next packet object in queue.
1823 *
1824 * Inputs: Packet object.
1825 *
1826 * Returns: Following object in queue or NULL.
1827 *
1828 *------------------------------------------------------------------------------*/
1829
ax25_get_nextp(packet_t this_p)1830 packet_t ax25_get_nextp (packet_t this_p)
1831 {
1832 assert (this_p->magic1 == MAGIC);
1833 assert (this_p->magic2 == MAGIC);
1834
1835 return (this_p->nextp);
1836 }
1837
1838
1839 /*------------------------------------------------------------------------------
1840 *
1841 * Name: ax25_set_release_time
1842 *
1843 * Purpose: Set release time
1844 *
1845 * Inputs: this_p - Current packet object.
1846 *
1847 * release_time - Time as returned by dtime_now().
1848 *
1849 *------------------------------------------------------------------------------*/
1850
ax25_set_release_time(packet_t this_p,double release_time)1851 void ax25_set_release_time (packet_t this_p, double release_time)
1852 {
1853 assert (this_p->magic1 == MAGIC);
1854 assert (this_p->magic2 == MAGIC);
1855
1856 this_p->release_time = release_time;
1857 }
1858
1859
1860
1861 /*------------------------------------------------------------------------------
1862 *
1863 * Name: ax25_get_release_time
1864 *
1865 * Purpose: Get release time.
1866 *
1867 *------------------------------------------------------------------------------*/
1868
ax25_get_release_time(packet_t this_p)1869 double ax25_get_release_time (packet_t this_p)
1870 {
1871 assert (this_p->magic1 == MAGIC);
1872 assert (this_p->magic2 == MAGIC);
1873
1874 return (this_p->release_time);
1875 }
1876
1877
1878 /*------------------------------------------------------------------------------
1879 *
1880 * Name: ax25_set_modulo
1881 *
1882 * Purpose: Set modulo value for I and S frame sequence numbers.
1883 *
1884 *------------------------------------------------------------------------------*/
1885
ax25_set_modulo(packet_t this_p,int modulo)1886 void ax25_set_modulo (packet_t this_p, int modulo)
1887 {
1888 assert (this_p->magic1 == MAGIC);
1889 assert (this_p->magic2 == MAGIC);
1890
1891 this_p->modulo = modulo;
1892 }
1893
1894
1895
1896
1897
1898 /*------------------------------------------------------------------
1899 *
1900 * Function: ax25_format_addrs
1901 *
1902 * Purpose: Format all the addresses suitable for printing.
1903 *
1904 * The AX.25 spec refers to this as "Source Path Header" - "TNC-2" Format
1905 *
1906 * Inputs: Current packet.
1907 *
1908 * Outputs: result - All addresses combined into a single string of the form:
1909 *
1910 * "Source > Destination [ , repeater ... ] :"
1911 *
1912 * An asterisk is displayed after the last digipeater
1913 * with the "H" bit set. e.g. If we hear RPT2,
1914 *
1915 * SRC>DST,RPT1,RPT2*,RPT3:
1916 *
1917 * No asterisk means the source is being heard directly.
1918 * Needs to be 101 characters to avoid overflowing.
1919 * (Up to 100 characters + \0)
1920 *
1921 * Errors: No error checking so caller needs to be careful.
1922 *
1923 *
1924 *------------------------------------------------------------------*/
1925
1926 // TODO: max len for result. buffer overflow?
1927
ax25_format_addrs(packet_t this_p,char * result)1928 void ax25_format_addrs (packet_t this_p, char *result)
1929 {
1930 int i;
1931 int heard;
1932 char stemp[AX25_MAX_ADDR_LEN];
1933
1934 assert (this_p->magic1 == MAGIC);
1935 assert (this_p->magic2 == MAGIC);
1936 *result = '\0';
1937
1938 /* New in 0.9. */
1939 /* Don't get upset if no addresses. */
1940 /* This will allow packets that do not comply to AX.25 format. */
1941
1942 if (this_p->num_addr == 0) {
1943 return;
1944 }
1945
1946 ax25_get_addr_with_ssid (this_p, AX25_SOURCE, stemp);
1947 strcat (result, stemp);
1948 strcat (result, ">");
1949
1950 ax25_get_addr_with_ssid (this_p, AX25_DESTINATION, stemp);
1951 strcat (result, stemp);
1952
1953 heard = ax25_get_heard(this_p);
1954
1955 for (i=(int)AX25_REPEATER_1; i<this_p->num_addr; i++) {
1956 ax25_get_addr_with_ssid (this_p, i, stemp);
1957 strcat (result, ",");
1958 strcat (result, stemp);
1959 if (i == heard) {
1960 strcat (result, "*");
1961 }
1962 }
1963
1964 strcat (result, ":");
1965
1966 // dw_printf ("DEBUG ax25_format_addrs, num_addr = %d, result = '%s'\n", this_p->num_addr, result);
1967 }
1968
1969
1970 /*------------------------------------------------------------------
1971 *
1972 * Function: ax25_format_via_path
1973 *
1974 * Purpose: Format via path addresses suitable for printing.
1975 *
1976 * Inputs: Current packet.
1977 *
1978 * result_size - Number of bytes available for result.
1979 * We can have up to 8 addresses x 9 characters
1980 * plus 7 commas, possible *, and nul = 81 minimum.
1981 *
1982 * Outputs: result - Digipeater field addresses combined into a single string of the form:
1983 *
1984 * "repeater, repeater ..."
1985 *
1986 * An asterisk is displayed after the last digipeater
1987 * with the "H" bit set. e.g. If we hear RPT2,
1988 *
1989 * RPT1,RPT2*,RPT3
1990 *
1991 * No asterisk means the source is being heard directly.
1992 *
1993 *------------------------------------------------------------------*/
1994
ax25_format_via_path(packet_t this_p,char * result,size_t result_size)1995 void ax25_format_via_path (packet_t this_p, char *result, size_t result_size)
1996 {
1997 int i;
1998 int heard;
1999 char stemp[AX25_MAX_ADDR_LEN];
2000
2001 assert (this_p->magic1 == MAGIC);
2002 assert (this_p->magic2 == MAGIC);
2003 *result = '\0';
2004
2005 /* Don't get upset if no addresses. */
2006 /* This will allow packets that do not comply to AX.25 format. */
2007
2008 if (this_p->num_addr == 0) {
2009 return;
2010 }
2011
2012 heard = ax25_get_heard(this_p);
2013
2014 for (i=(int)AX25_REPEATER_1; i<this_p->num_addr; i++) {
2015 if (i > (int)AX25_REPEATER_1) {
2016 strlcat (result, ",", result_size);
2017 }
2018 ax25_get_addr_with_ssid (this_p, i, stemp);
2019 strlcat (result, stemp, result_size);
2020 if (i == heard) {
2021 strlcat (result, "*", result_size);
2022 }
2023 }
2024
2025 } /* end ax25_format_via_path */
2026
2027
2028 /*------------------------------------------------------------------
2029 *
2030 * Function: ax25_pack
2031 *
2032 * Purpose: Put all the pieces into format ready for transmission.
2033 *
2034 * Inputs: this_p - pointer to packet object.
2035 *
2036 * Outputs: result - Frame buffer, AX25_MAX_PACKET_LEN bytes.
2037 * Should also have two extra for FCS to be
2038 * added later.
2039 *
2040 * Returns: Number of octets in the frame buffer.
2041 * Does NOT include the extra 2 for FCS.
2042 *
2043 * Errors: Returns -1.
2044 *
2045 *------------------------------------------------------------------*/
2046
ax25_pack(packet_t this_p,unsigned char result[AX25_MAX_PACKET_LEN])2047 int ax25_pack (packet_t this_p, unsigned char result[AX25_MAX_PACKET_LEN])
2048 {
2049
2050 assert (this_p->magic1 == MAGIC);
2051 assert (this_p->magic2 == MAGIC);
2052
2053 assert (this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN);
2054
2055 memcpy (result, this_p->frame_data, this_p->frame_len);
2056
2057 return (this_p->frame_len);
2058 }
2059
2060
2061
2062 /*------------------------------------------------------------------
2063 *
2064 * Function: ax25_frame_type
2065 *
2066 * Purpose: Extract the type of frame.
2067 * This is derived from the control byte(s) but
2068 * is an enumerated type for easier handling.
2069 *
2070 * Inputs: this_p - pointer to packet object.
2071 *
2072 * Outputs: desc - Text description such as "I frame" or
2073 * "U frame SABME".
2074 * Supply 56 bytes to be safe.
2075 *
2076 * cr - Command or response?
2077 *
2078 * pf - P/F - Poll/Final or -1 if not applicable
2079 *
2080 * nr - N(R) - receive sequence or -1 if not applicable.
2081 *
2082 * ns - N(S) - send sequence or -1 if not applicable.
2083 *
2084 * Returns: Frame type from enum ax25_frame_type_e.
2085 *
2086 *------------------------------------------------------------------*/
2087
2088 // TODO: need someway to ensure caller allocated enough space.
2089 // Should pass in as parameter.
2090 #define DESC_SIZ 56
2091
2092
ax25_frame_type(packet_t this_p,cmdres_t * cr,char * desc,int * pf,int * nr,int * ns)2093 ax25_frame_type_t ax25_frame_type (packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns)
2094 {
2095 int c; // U frames are always one control byte.
2096 int c2 = 0; // I & S frames can have second Control byte.
2097
2098 assert (this_p->magic1 == MAGIC);
2099 assert (this_p->magic2 == MAGIC);
2100
2101 strlcpy (desc, "????", DESC_SIZ);
2102 *cr = cr_11;
2103 *pf = -1;
2104 *nr = -1;
2105 *ns = -1;
2106
2107 c = ax25_get_control(this_p);
2108 if (c < 0) {
2109 strlcpy (desc, "Not AX.25", DESC_SIZ);
2110 return (frame_not_AX25);
2111 }
2112
2113 /*
2114 * TERRIBLE HACK :-( for display purposes.
2115 *
2116 * I and S frames can have 1 or 2 control bytes but there is
2117 * no good way to determine this without dipping into the data
2118 * link state machine. Can we guess?
2119 *
2120 * S frames have no protocol id or information so if there is one
2121 * more byte beyond the control field, we could assume there are
2122 * two control bytes.
2123 *
2124 * For I frames, the protocol id will usually be 0xf0. If we find
2125 * that as the first byte of the information field, it is probably
2126 * the pid and not part of the information. Ditto for segments 0x08.
2127 * Not fool proof but good enough for troubleshooting text out.
2128 *
2129 * If we have a link to the peer station, this will be set properly
2130 * before it needs to be used for other reasons.
2131 *
2132 * Setting one of the RR bits (find reference!) is sounding better and better.
2133 * It's in common usage so I should lobby to get that in the official protocol spec.
2134 */
2135
2136 if (this_p->modulo == 0 && (c & 3) == 1 && ax25_get_c2(this_p) != -1) {
2137 this_p->modulo = modulo_128;
2138 }
2139 else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0xF0) {
2140 this_p->modulo = modulo_128;
2141 }
2142 else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0x08) { // same for segments
2143 this_p->modulo = modulo_128;
2144 }
2145
2146
2147 if (this_p->modulo == modulo_128) {
2148 c2 = ax25_get_c2 (this_p);
2149 }
2150
2151 int dst_c = this_p->frame_data[AX25_DESTINATION * 7 + 6] & SSID_H_MASK;
2152 int src_c = this_p->frame_data[AX25_SOURCE * 7 + 6] & SSID_H_MASK;
2153
2154 char cr_text[8];
2155 char pf_text[8];
2156
2157 if (dst_c) {
2158 if (src_c) { *cr = cr_11; strcpy(cr_text,"cc=11"); strcpy(pf_text,"p/f"); }
2159 else { *cr = cr_cmd; strcpy(cr_text,"cmd"); strcpy(pf_text,"p"); }
2160 }
2161 else {
2162 if (src_c) { *cr = cr_res; strcpy(cr_text,"res"); strcpy(pf_text,"f"); }
2163 else { *cr = cr_00; strcpy(cr_text,"cc=00"); strcpy(pf_text,"p/f"); }
2164 }
2165
2166 if ((c & 1) == 0) {
2167
2168 // Information rrr p sss 0 or sssssss 0 rrrrrrr p
2169
2170 if (this_p->modulo == modulo_128) {
2171 *ns = (c >> 1) & 0x7f;
2172 *pf = c2 & 1;
2173 *nr = (c2 >> 1) & 0x7f;
2174 }
2175 else {
2176 *ns = (c >> 1) & 7;
2177 *pf = (c >> 4) & 1;
2178 *nr = (c >> 5) & 7;
2179 }
2180
2181 //snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d", cr_text, *ns, *nr, pf_text, *pf);
2182 snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d, pid=0x%02x", cr_text, *ns, *nr, pf_text, *pf, ax25_get_pid(this_p));
2183 return (frame_type_I);
2184 }
2185 else if ((c & 2) == 0) {
2186
2187 // Supervisory rrr p/f ss 0 1 or 0000 ss 0 1 rrrrrrr p/f
2188
2189 if (this_p->modulo == modulo_128) {
2190 *pf = c2 & 1;
2191 *nr = (c2 >> 1) & 0x7f;
2192 }
2193 else {
2194 *pf = (c >> 4) & 1;
2195 *nr = (c >> 5) & 7;
2196 }
2197
2198
2199 switch ((c >> 2) & 3) {
2200 case 0: snprintf (desc, DESC_SIZ, "RR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RR); break;
2201 case 1: snprintf (desc, DESC_SIZ, "RNR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RNR); break;
2202 case 2: snprintf (desc, DESC_SIZ, "REJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_REJ); break;
2203 case 3: snprintf (desc, DESC_SIZ, "SREJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_SREJ); break;
2204 }
2205 }
2206 else {
2207
2208 // Unnumbered mmm p/f mm 1 1
2209
2210 *pf = (c >> 4) & 1;
2211
2212 switch (c & 0xef) {
2213
2214 case 0x6f: snprintf (desc, DESC_SIZ, "SABME %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABME); break;
2215 case 0x2f: snprintf (desc, DESC_SIZ, "SABM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABM); break;
2216 case 0x43: snprintf (desc, DESC_SIZ, "DISC %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DISC); break;
2217 case 0x0f: snprintf (desc, DESC_SIZ, "DM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DM); break;
2218 case 0x63: snprintf (desc, DESC_SIZ, "UA %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UA); break;
2219 case 0x87: snprintf (desc, DESC_SIZ, "FRMR %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_FRMR); break;
2220 case 0x03: snprintf (desc, DESC_SIZ, "UI %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UI); break;
2221 case 0xaf: snprintf (desc, DESC_SIZ, "XID %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_XID); break;
2222 case 0xe3: snprintf (desc, DESC_SIZ, "TEST %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_TEST); break;
2223 default: snprintf (desc, DESC_SIZ, "U other???"); return (frame_type_U); break;
2224 }
2225 }
2226
2227 // Should be unreachable but compiler doesn't realize that.
2228 // Here only to suppress "warning: control reaches end of non-void function"
2229
2230 return (frame_not_AX25);
2231
2232 } /* end ax25_frame_type */
2233
2234
2235
2236 /*------------------------------------------------------------------
2237 *
2238 * Function: ax25_hex_dump
2239 *
2240 * Purpose: Print out packet in hexadecimal for debugging.
2241 *
2242 * Inputs: fptr - Pointer to frame data.
2243 *
2244 * flen - Frame length, bytes. Does not include CRC.
2245 *
2246 *------------------------------------------------------------------*/
2247
hex_dump(unsigned char * p,int len)2248 static void hex_dump (unsigned char *p, int len)
2249 {
2250 int n, i, offset;
2251
2252 offset = 0;
2253 while (len > 0) {
2254 n = len < 16 ? len : 16;
2255 dw_printf (" %03x: ", offset);
2256 for (i=0; i<n; i++) {
2257 dw_printf (" %02x", p[i]);
2258 }
2259 for (i=n; i<16; i++) {
2260 dw_printf (" ");
2261 }
2262 dw_printf (" ");
2263 for (i=0; i<n; i++) {
2264 dw_printf ("%c", isprint(p[i]) ? p[i] : '.');
2265 }
2266 dw_printf ("\n");
2267 p += 16;
2268 offset += 16;
2269 len -= 16;
2270 }
2271 }
2272
2273 /* Text description of control octet. */
2274 // FIXME: this is wrong. It doesn't handle modulo 128.
2275
2276 // TODO: use ax25_frame_type() instead.
2277
ctrl_to_text(int c,char * out,size_t outsiz)2278 static void ctrl_to_text (int c, char *out, size_t outsiz)
2279 {
2280 if ((c & 1) == 0) { snprintf (out, outsiz, "I frame: n(r)=%d, p=%d, n(s)=%d", (c>>5)&7, (c>>4)&1, (c>>1)&7); }
2281 else if ((c & 0xf) == 0x01) { snprintf (out, outsiz, "S frame RR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
2282 else if ((c & 0xf) == 0x05) { snprintf (out, outsiz, "S frame RNR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
2283 else if ((c & 0xf) == 0x09) { snprintf (out, outsiz, "S frame REJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
2284 else if ((c & 0xf) == 0x0D) { snprintf (out, outsiz, "S frame sREJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
2285 else if ((c & 0xef) == 0x6f) { snprintf (out, outsiz, "U frame SABME: p=%d", (c>>4)&1); }
2286 else if ((c & 0xef) == 0x2f) { snprintf (out, outsiz, "U frame SABM: p=%d", (c>>4)&1); }
2287 else if ((c & 0xef) == 0x43) { snprintf (out, outsiz, "U frame DISC: p=%d", (c>>4)&1); }
2288 else if ((c & 0xef) == 0x0f) { snprintf (out, outsiz, "U frame DM: f=%d", (c>>4)&1); }
2289 else if ((c & 0xef) == 0x63) { snprintf (out, outsiz, "U frame UA: f=%d", (c>>4)&1); }
2290 else if ((c & 0xef) == 0x87) { snprintf (out, outsiz, "U frame FRMR: f=%d", (c>>4)&1); }
2291 else if ((c & 0xef) == 0x03) { snprintf (out, outsiz, "U frame UI: p/f=%d", (c>>4)&1); }
2292 else if ((c & 0xef) == 0xAF) { snprintf (out, outsiz, "U frame XID: p/f=%d", (c>>4)&1); }
2293 else if ((c & 0xef) == 0xe3) { snprintf (out, outsiz, "U frame TEST: p/f=%d", (c>>4)&1); }
2294 else { snprintf (out, outsiz, "Unknown frame type for control = 0x%02x", c); }
2295 }
2296
2297 /* Text description of protocol id octet. */
2298
2299 #define PID_TEXT_SIZE 80
2300
pid_to_text(int p,char out[PID_TEXT_SIZE])2301 static void pid_to_text (int p, char out[PID_TEXT_SIZE])
2302 {
2303
2304 if ((p & 0x30) == 0x10) { snprintf (out, PID_TEXT_SIZE, "AX.25 layer 3 implemented."); }
2305 else if ((p & 0x30) == 0x20) { snprintf (out, PID_TEXT_SIZE, "AX.25 layer 3 implemented."); }
2306 else if (p == 0x01) { snprintf (out, PID_TEXT_SIZE, "ISO 8208/CCITT X.25 PLP"); }
2307 else if (p == 0x06) { snprintf (out, PID_TEXT_SIZE, "Compressed TCP/IP packet. Van Jacobson (RFC 1144)"); }
2308 else if (p == 0x07) { snprintf (out, PID_TEXT_SIZE, "Uncompressed TCP/IP packet. Van Jacobson (RFC 1144)"); }
2309 else if (p == 0x08) { snprintf (out, PID_TEXT_SIZE, "Segmentation fragment"); }
2310 else if (p == 0xC3) { snprintf (out, PID_TEXT_SIZE, "TEXNET datagram protocol"); }
2311 else if (p == 0xC4) { snprintf (out, PID_TEXT_SIZE, "Link Quality Protocol"); }
2312 else if (p == 0xCA) { snprintf (out, PID_TEXT_SIZE, "Appletalk"); }
2313 else if (p == 0xCB) { snprintf (out, PID_TEXT_SIZE, "Appletalk ARP"); }
2314 else if (p == 0xCC) { snprintf (out, PID_TEXT_SIZE, "ARPA Internet Protocol"); }
2315 else if (p == 0xCD) { snprintf (out, PID_TEXT_SIZE, "ARPA Address resolution"); }
2316 else if (p == 0xCE) { snprintf (out, PID_TEXT_SIZE, "FlexNet"); }
2317 else if (p == 0xCF) { snprintf (out, PID_TEXT_SIZE, "NET/ROM"); }
2318 else if (p == 0xF0) { snprintf (out, PID_TEXT_SIZE, "No layer 3 protocol implemented."); }
2319 else if (p == 0xFF) { snprintf (out, PID_TEXT_SIZE, "Escape character. Next octet contains more Level 3 protocol information."); }
2320 else { snprintf (out, PID_TEXT_SIZE, "Unknown protocol id = 0x%02x", p); }
2321 }
2322
2323
2324
ax25_hex_dump(packet_t this_p)2325 void ax25_hex_dump (packet_t this_p)
2326 {
2327 int n;
2328 unsigned char *fptr = this_p->frame_data;
2329 int flen = this_p->frame_len;
2330
2331
2332
2333 if (this_p->num_addr >= AX25_MIN_ADDRS && this_p->num_addr <= AX25_MAX_ADDRS) {
2334 int c, p;
2335 char cp_text[120];
2336 char l_text[20];
2337
2338 c = fptr[this_p->num_addr*7];
2339 p = fptr[this_p->num_addr*7+1];
2340
2341 ctrl_to_text (c, cp_text, sizeof(cp_text)); // TODO: use ax25_frame_type() instead.
2342
2343 if ( (c & 0x01) == 0 || /* I xxxx xxx0 */
2344 c == 0x03 || c == 0x13) { /* UI 000x 0011 */
2345
2346 char pid_text[PID_TEXT_SIZE];
2347
2348 pid_to_text (p, pid_text);
2349
2350 strlcat (cp_text, ", ", sizeof(cp_text));
2351 strlcat (cp_text, pid_text, sizeof(cp_text));
2352
2353 }
2354
2355 snprintf (l_text, sizeof(l_text), ", length = %d", flen);
2356 strlcat (cp_text, l_text, sizeof(cp_text));
2357
2358 dw_printf ("%s\n", cp_text);
2359 }
2360
2361 // Address fields must be only upper case letters and digits.
2362 // If less than 6 characters, trailing positions are filled with ASCII space.
2363 // Using all zero bits in one of these 6 positions is wrong.
2364 // Any non printable characters will be printed as "." here.
2365
2366 dw_printf (" dest %c%c%c%c%c%c %2d c/r=%d res=%d last=%d\n",
2367 isprint(fptr[0]>>1) ? fptr[0]>>1 : '.',
2368 isprint(fptr[1]>>1) ? fptr[1]>>1 : '.',
2369 isprint(fptr[2]>>1) ? fptr[2]>>1 : '.',
2370 isprint(fptr[3]>>1) ? fptr[3]>>1 : '.',
2371 isprint(fptr[4]>>1) ? fptr[4]>>1 : '.',
2372 isprint(fptr[5]>>1) ? fptr[5]>>1 : '.',
2373 (fptr[6]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
2374 (fptr[6]&SSID_H_MASK)>>SSID_H_SHIFT,
2375 (fptr[6]&SSID_RR_MASK)>>SSID_RR_SHIFT,
2376 fptr[6]&SSID_LAST_MASK);
2377
2378 dw_printf (" source %c%c%c%c%c%c %2d c/r=%d res=%d last=%d\n",
2379 isprint(fptr[7]>>1) ? fptr[7]>>1 : '.',
2380 isprint(fptr[8]>>1) ? fptr[8]>>1 : '.',
2381 isprint(fptr[9]>>1) ? fptr[9]>>1 : '.',
2382 isprint(fptr[10]>>1) ? fptr[10]>>1 : '.',
2383 isprint(fptr[11]>>1) ? fptr[11]>>1 : '.',
2384 isprint(fptr[12]>>1) ? fptr[12]>>1 : '.',
2385 (fptr[13]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
2386 (fptr[13]&SSID_H_MASK)>>SSID_H_SHIFT,
2387 (fptr[13]&SSID_RR_MASK)>>SSID_RR_SHIFT,
2388 fptr[13]&SSID_LAST_MASK);
2389
2390 for (n=2; n<this_p->num_addr; n++) {
2391
2392 dw_printf (" digi %d %c%c%c%c%c%c %2d h=%d res=%d last=%d\n",
2393 n - 1,
2394 isprint(fptr[n*7+0]>>1) ? fptr[n*7+0]>>1 : '.',
2395 isprint(fptr[n*7+1]>>1) ? fptr[n*7+1]>>1 : '.',
2396 isprint(fptr[n*7+2]>>1) ? fptr[n*7+2]>>1 : '.',
2397 isprint(fptr[n*7+3]>>1) ? fptr[n*7+3]>>1 : '.',
2398 isprint(fptr[n*7+4]>>1) ? fptr[n*7+4]>>1 : '.',
2399 isprint(fptr[n*7+5]>>1) ? fptr[n*7+5]>>1 : '.',
2400 (fptr[n*7+6]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
2401 (fptr[n*7+6]&SSID_H_MASK)>>SSID_H_SHIFT,
2402 (fptr[n*7+6]&SSID_RR_MASK)>>SSID_RR_SHIFT,
2403 fptr[n*7+6]&SSID_LAST_MASK);
2404
2405 }
2406
2407 hex_dump (fptr, flen);
2408
2409 } /* end ax25_hex_dump */
2410
2411
2412
2413 /*------------------------------------------------------------------
2414 *
2415 * Function: ax25_is_aprs
2416 *
2417 * Purpose: Is this packet APRS format?
2418 *
2419 * Inputs: this_p - pointer to packet object.
2420 *
2421 * Returns: True if this frame has the proper control
2422 * octets for an APRS packet.
2423 * control 3 for UI frame
2424 * protocol id 0xf0 for no layer 3
2425 *
2426 *
2427 * Description: Dire Wolf should be able to act as a KISS TNC for
2428 * any type of AX.25 activity. However, there are other
2429 * places where we want to process only APRS.
2430 * (e.g. digipeating and IGate.)
2431 *
2432 *------------------------------------------------------------------*/
2433
2434
ax25_is_aprs(packet_t this_p)2435 int ax25_is_aprs (packet_t this_p)
2436 {
2437 int ctrl, pid, is_aprs;
2438
2439 assert (this_p->magic1 == MAGIC);
2440 assert (this_p->magic2 == MAGIC);
2441
2442 if (this_p->frame_len == 0) return(0);
2443
2444 ctrl = ax25_get_control(this_p);
2445 pid = ax25_get_pid(this_p);
2446
2447 is_aprs = this_p->num_addr >= 2 && ctrl == AX25_UI_FRAME && pid == AX25_PID_NO_LAYER_3;
2448
2449 #if 0
2450 text_color_set(DW_COLOR_ERROR);
2451 dw_printf ("ax25_is_aprs(): ctrl=%02x, pid=%02x, is_aprs=%d\n", ctrl, pid, is_aprs);
2452 #endif
2453 return (is_aprs);
2454 }
2455
2456
2457 /*------------------------------------------------------------------
2458 *
2459 * Function: ax25_is_null_frame
2460 *
2461 * Purpose: Is this packet structure empty?
2462 *
2463 * Inputs: this_p - pointer to packet object.
2464 *
2465 * Returns: True if frame data length is 0.
2466 *
2467 * Description: This is used when we want to wake up the
2468 * transmit queue processing thread but don't
2469 * want to transmit a frame.
2470 *
2471 *------------------------------------------------------------------*/
2472
2473
ax25_is_null_frame(packet_t this_p)2474 int ax25_is_null_frame (packet_t this_p)
2475 {
2476 int is_null;
2477
2478 assert (this_p->magic1 == MAGIC);
2479 assert (this_p->magic2 == MAGIC);
2480
2481 is_null = this_p->frame_len == 0;
2482
2483 #if 0
2484 text_color_set(DW_COLOR_ERROR);
2485 dw_printf ("ax25_is_null_frame(): is_null=%d\n", is_null);
2486 #endif
2487 return (is_null);
2488 }
2489
2490
2491 /*------------------------------------------------------------------
2492 *
2493 * Function: ax25_get_control
2494 ax25_get_c2
2495 *
2496 * Purpose: Get Control field from packet.
2497 *
2498 * Inputs: this_p - pointer to packet object.
2499 *
2500 * Returns: APRS uses AX25_UI_FRAME.
2501 * This could also be used in other situations.
2502 *
2503 *------------------------------------------------------------------*/
2504
2505
ax25_get_control(packet_t this_p)2506 int ax25_get_control (packet_t this_p)
2507 {
2508 assert (this_p->magic1 == MAGIC);
2509 assert (this_p->magic2 == MAGIC);
2510
2511 if (this_p->frame_len == 0) return(-1);
2512
2513 if (this_p->num_addr >= 2) {
2514 return (this_p->frame_data[ax25_get_control_offset(this_p)]);
2515 }
2516 return (-1);
2517 }
2518
ax25_get_c2(packet_t this_p)2519 int ax25_get_c2 (packet_t this_p)
2520 {
2521 assert (this_p->magic1 == MAGIC);
2522 assert (this_p->magic2 == MAGIC);
2523
2524 if (this_p->frame_len == 0) return(-1);
2525
2526 if (this_p->num_addr >= 2) {
2527 int offset2 = ax25_get_control_offset(this_p)+1;
2528
2529 if (offset2 < this_p->frame_len) {
2530 return (this_p->frame_data[offset2]);
2531 }
2532 else {
2533 return (-1); /* attempt to go beyond the end of frame. */
2534 }
2535 }
2536 return (-1); /* not AX.25 */
2537 }
2538
2539
2540 /*------------------------------------------------------------------
2541 *
2542 * Function: ax25_get_pid
2543 *
2544 * Purpose: Get protocol ID from packet.
2545 *
2546 * Inputs: this_p - pointer to packet object.
2547 *
2548 * Returns: APRS uses 0xf0 for no layer 3.
2549 * This could also be used in other situations.
2550 *
2551 * AX.25: "The Protocol Identifier (PID) field appears in information
2552 * frames (I and UI) only. It identifies which kind of
2553 * Layer 3 protocol, if any, is in use."
2554 *
2555 *------------------------------------------------------------------*/
2556
2557
ax25_get_pid(packet_t this_p)2558 int ax25_get_pid (packet_t this_p)
2559 {
2560 assert (this_p->magic1 == MAGIC);
2561 assert (this_p->magic2 == MAGIC);
2562
2563 // TODO: handle 2 control byte case.
2564 // TODO: sanity check: is it I or UI frame?
2565
2566 if (this_p->frame_len == 0) return(-1);
2567
2568 if (this_p->num_addr >= 2) {
2569 return (this_p->frame_data[ax25_get_pid_offset(this_p)]);
2570 }
2571 return (-1);
2572 }
2573
2574
2575
2576 /*------------------------------------------------------------------
2577 *
2578 * Function: ax25_get_frame_len
2579 *
2580 * Purpose: Get length of frame.
2581 *
2582 * Inputs: this_p - pointer to packet object.
2583 *
2584 * Returns: Number of octets in the frame buffer.
2585 * Does NOT include the extra 2 for FCS.
2586 *
2587 *------------------------------------------------------------------*/
2588
ax25_get_frame_len(packet_t this_p)2589 int ax25_get_frame_len (packet_t this_p)
2590 {
2591 assert (this_p->magic1 == MAGIC);
2592 assert (this_p->magic2 == MAGIC);
2593
2594 assert (this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN);
2595
2596 return (this_p->frame_len);
2597
2598 } /* end ax25_get_frame_len */
2599
2600
2601
2602 /*------------------------------------------------------------------------------
2603 *
2604 * Name: ax25_dedupe_crc
2605 *
2606 * Purpose: Calculate a checksum for the packet source, destination, and
2607 * information but NOT the digipeaters.
2608 * This is used for duplicate detection in the digipeater
2609 * and IGate algorithms.
2610 *
2611 * Input: pp - Pointer to packet object.
2612 *
2613 * Returns: Value which will be the same for a duplicate but very unlikely
2614 * to match a non-duplicate packet.
2615 *
2616 * Description: For detecting duplicates, we need to look
2617 * + source station
2618 * + destination
2619 * + information field
2620 * but NOT the changing list of digipeaters.
2621 *
2622 * Typically, only a checksum is kept to reduce memory
2623 * requirements and amount of compution for comparisons.
2624 * There is a very very small probability that two unrelated
2625 * packets will result in the same checksum, and the
2626 * undesired dropping of the packet.
2627 *
2628 * There is a 1 / 65536 chance of getting a false positive match
2629 * which is good enough for this application.
2630 * We could reduce that with a 32 bit CRC instead of reusing
2631 * code from the AX.25 frame CRC calculation.
2632 *
2633 * Version 1.3: We exclude any trailing CR/LF at the end of the info part
2634 * so we can detect duplicates that are received only over the
2635 * air and those which have gone thru an IGate where the process
2636 * removes any trailing CR/LF. Example:
2637 *
2638 * Original via RF only:
2639 * W1TG-1>APU25N,N3LEE-10*,WIDE2-1:<IGATE,MSG_CNT=30,LOC_CNT=61<0x0d>
2640 *
2641 * When we get the same thing via APRS-IS:
2642 * W1TG-1>APU25N,K1FFK,WIDE2*,qAR,WB2ZII-15:<IGATE,MSG_CNT=30,LOC_CNT=61
2643 *
2644 * (Actually there is a trailing space. Maybe some systems
2645 * change control characters to space???)
2646 * Hmmmm. I guess we should ignore trailing space as well for
2647 * duplicate detection and suppression.
2648 *
2649 *------------------------------------------------------------------------------*/
2650
ax25_dedupe_crc(packet_t pp)2651 unsigned short ax25_dedupe_crc (packet_t pp)
2652 {
2653 unsigned short crc;
2654 char src[AX25_MAX_ADDR_LEN];
2655 char dest[AX25_MAX_ADDR_LEN];
2656 unsigned char *pinfo;
2657 int info_len;
2658
2659 ax25_get_addr_with_ssid(pp, AX25_SOURCE, src);
2660 ax25_get_addr_with_ssid(pp, AX25_DESTINATION, dest);
2661 info_len = ax25_get_info (pp, &pinfo);
2662
2663 while (info_len >= 1 && (pinfo[info_len-1] == '\r' ||
2664 pinfo[info_len-1] == '\n' ||
2665 pinfo[info_len-1] == ' ')) {
2666
2667 // Temporary for debugging!
2668
2669 // if (pinfo[info_len-1] == ' ') {
2670 // text_color_set(DW_COLOR_ERROR);
2671 // dw_printf ("DEBUG: ax25_dedupe_crc ignoring trailing space.\n");
2672 // }
2673
2674 info_len--;
2675 }
2676
2677 crc = 0xffff;
2678 crc = crc16((unsigned char *)src, strlen(src), crc);
2679 crc = crc16((unsigned char *)dest, strlen(dest), crc);
2680 crc = crc16(pinfo, info_len, crc);
2681
2682 return (crc);
2683 }
2684
2685 /*------------------------------------------------------------------------------
2686 *
2687 * Name: ax25_m_m_crc
2688 *
2689 * Purpose: Calculate a checksum for the packet.
2690 * This is used for the multimodem duplicate detection.
2691 *
2692 * Input: pp - Pointer to packet object.
2693 *
2694 * Returns: Value which will be the same for a duplicate but very unlikely
2695 * to match a non-duplicate packet.
2696 *
2697 * Description: For detecting duplicates, we need to look the entire packet.
2698 *
2699 * Typically, only a checksum is kept to reduce memory
2700 * requirements and amount of compution for comparisons.
2701 * There is a very very small probability that two unrelated
2702 * packets will result in the same checksum, and the
2703 * undesired dropping of the packet.
2704
2705 *------------------------------------------------------------------------------*/
2706
ax25_m_m_crc(packet_t pp)2707 unsigned short ax25_m_m_crc (packet_t pp)
2708 {
2709 unsigned short crc;
2710 unsigned char fbuf[AX25_MAX_PACKET_LEN];
2711 int flen;
2712
2713 flen = ax25_pack (pp, fbuf);
2714
2715 crc = 0xffff;
2716 crc = crc16(fbuf, flen, crc);
2717
2718 return (crc);
2719 }
2720
2721
2722 /*------------------------------------------------------------------
2723 *
2724 * Function: ax25_safe_print
2725 *
2726 * Purpose: Print given string, changing non printable characters to
2727 * hexadecimal notation. Note that character values
2728 * <DEL>, 28, 29, 30, and 31 can appear in MIC-E message.
2729 *
2730 * Inputs: pstr - Pointer to string.
2731 *
2732 * len - Number of bytes. If < 0 we use strlen().
2733 *
2734 * ascii_only - Restrict output to only ASCII.
2735 * Normally we allow UTF-8.
2736 *
2737 * Stops after non-zero len characters or at nul.
2738 *
2739 * Returns: none
2740 *
2741 * Description: Print a string in a "safe" manner.
2742 * Anything that is not a printable character
2743 * will be converted to a hexadecimal representation.
2744 * For example, a Line Feed character will appear as <0x0a>
2745 * rather than dropping down to the next line on the screen.
2746 *
2747 * ax25_from_text can accept this format.
2748 *
2749 *
2750 * Example: W1MED-1>T2QP0S,N1OHZ,N8VIM*,WIDE1-1:'cQBl <0x1c>-/]<0x0d>
2751 * ------ ------
2752 *
2753 * Questions: What should we do about UTF-8? Should that be displayed
2754 * as hexadecimal for troubleshooting? Maybe an option so the
2755 * packet raw data is in hexadecimal but an extracted
2756 * comment displays UTF-8? Or a command line option for only ASCII?
2757 *
2758 * Trailing space:
2759 * I recently noticed a case where a packet has space character
2760 * at the end. If the last character of the line is a space,
2761 * this will be displayed in hexadecimal to make it obvious.
2762 *
2763 *------------------------------------------------------------------*/
2764
2765 #define MAXSAFE 500
2766
ax25_safe_print(char * pstr,int len,int ascii_only)2767 void ax25_safe_print (char *pstr, int len, int ascii_only)
2768 {
2769 int ch;
2770 char safe_str[MAXSAFE*6+1];
2771 int safe_len;
2772
2773 safe_len = 0;
2774 safe_str[safe_len] = '\0';
2775
2776
2777 if (len < 0)
2778 len = strlen(pstr);
2779
2780 if (len > MAXSAFE)
2781 len = MAXSAFE;
2782
2783 while (len > 0)
2784 {
2785 ch = *((unsigned char *)pstr);
2786
2787 if (ch == ' ' && (len == 1 || pstr[1] == '\0')) {
2788
2789 snprintf (safe_str + safe_len, sizeof(safe_str)-safe_len, "<0x%02x>", ch);
2790 safe_len += 6;
2791 }
2792 else if (ch < ' ' || ch == 0x7f || ch == 0xfe || ch == 0xff ||
2793 (ascii_only && ch >= 0x80) ) {
2794
2795 /* Control codes and delete. */
2796 /* UTF-8 does not use fe and ff except in a possible */
2797 /* "Byte Order Mark" (BOM) at the beginning. */
2798
2799 snprintf (safe_str + safe_len, sizeof(safe_str)-safe_len, "<0x%02x>", ch);
2800 safe_len += 6;
2801 }
2802 else {
2803 /* Let everything else thru so we can handle UTF-8 */
2804 /* Maybe we should have an option to display 0x80 */
2805 /* and above as hexadecimal. */
2806
2807 safe_str[safe_len++] = ch;
2808 safe_str[safe_len] = '\0';
2809 }
2810
2811 pstr++;
2812 len--;
2813 }
2814
2815 // TODO1.2: should return string rather printing to remove a race condition.
2816
2817 dw_printf ("%s", safe_str);
2818
2819 } /* end ax25_safe_print */
2820
2821
2822
2823 /*------------------------------------------------------------------
2824 *
2825 * Function: ax25_alevel_to_text
2826 *
2827 * Purpose: Convert audio level to text representation.
2828 *
2829 * Inputs: alevel - Audio levels collected from demodulator.
2830 *
2831 * Outputs: text - Text representation for presentation to user.
2832 * Currently it will look something like this:
2833 *
2834 * r(m/s)
2835 *
2836 * With n,m,s corresponding to received, mark, and space.
2837 * Comma is to be avoided because one place this
2838 * ends up is in a CSV format file.
2839 *
2840 * size should be AX25_ALEVEL_TO_TEXT_SIZE.
2841 *
2842 * Returns: True if something to print. (currently if alevel.original >= 0)
2843 * False if not.
2844 *
2845 * Description: Audio level used to be simple; it was a single number.
2846 * In version 1.2, we start collecting more details.
2847 * At the moment, it includes:
2848 *
2849 * - Received level from new method.
2850 * - Levels from mark & space filters to examine the ratio.
2851 *
2852 * We print this in multiple places so put it into a function.
2853 *
2854 *------------------------------------------------------------------*/
2855
2856
ax25_alevel_to_text(alevel_t alevel,char text[AX25_ALEVEL_TO_TEXT_SIZE])2857 int ax25_alevel_to_text (alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE])
2858 {
2859 if (alevel.rec < 0) {
2860 strlcpy (text, "", AX25_ALEVEL_TO_TEXT_SIZE);
2861 return (0);
2862 }
2863
2864 // TODO1.2: haven't thought much about non-AFSK cases yet.
2865 // What should we do for 9600 baud?
2866
2867 // For DTMF omit the two extra numbers.
2868
2869 if (alevel.mark >= 0 && alevel.space < 0) { /* baseband */
2870
2871 snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d(%+d/%+d)", alevel.rec, alevel.mark, alevel.space);
2872 }
2873 else if (alevel.mark == -1 && alevel.space == -1) { /* PSK - single number. */
2874
2875 snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d", alevel.rec);
2876 }
2877 else if (alevel.mark == -2 && alevel.space == -2) { /* DTMF - single number. */
2878
2879 snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d", alevel.rec);
2880 }
2881 else { /* AFSK */
2882
2883 //snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d:%d(%d/%d=%05.3f=)", alevel.original, alevel.rec, alevel.mark, alevel.space, alevel.ms_ratio);
2884 snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d(%d/%d)", alevel.rec, alevel.mark, alevel.space);
2885 }
2886 return (1);
2887
2888 } /* end ax25_alevel_to_text */
2889
2890
2891 /* end ax25_pad.c */
2892