1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 /*
25   AX.25 Parts adopted from: aprs_tty.c by Henk de Groot - PE1DNN
26 */
27 
28 
29 
30 #ifdef HAVE_CONFIG_H
31   #include "config.h"
32 #endif  // HAVE_CONFIG_H
33 
34 #include "snprintf.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <assert.h>
39 #include <ctype.h>
40 #include <sys/stat.h>
41 #include <sys/file.h>
42 #include <unistd.h>
43 #include <dirent.h>
44 #include <signal.h>
45 #include <termios.h>
46 #include <pwd.h>
47 #include <termios.h>
48 #include <setjmp.h>
49 #include <sys/socket.h>
50 #include <fcntl.h>
51 
52 #include <netinet/in.h>     // Moved ahead of inet.h as reports of some *BSD's not
53 // including this as they should.
54 #include <arpa/inet.h>
55 #include <netinet/tcp.h>    // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm)
56 
57 #ifdef HAVE_NETDB_H
58   #include <netdb.h>
59 #endif  // HAVE_NETDB_H
60 
61 #include <sys/types.h>
62 #include <sys/ioctl.h>
63 
64 #if TIME_WITH_SYS_TIME
65   #include <sys/time.h>
66   #include <time.h>
67 #else   // TIME_WITH_SYS_TIME
68   #if HAVE_SYS_TIME_H
69     #include <sys/time.h>
70   #else  // HAVE_SYS_TIME_H
71     #include <time.h>
72   #endif // HAVE_SYS_TIME_H
73 #endif  // TIME_WITH_SYS_TIME
74 
75 #include <errno.h>
76 
77 #ifdef  HAVE_LOCALE_H
78   #include <locale.h>
79 #endif  // HAVE_LOCALE_H
80 
81 #include <Xm/XmAll.h>
82 
83 #include "xastir.h"
84 #include "symbols.h"
85 #include "main.h"
86 #include "xa_config.h"
87 //#include "maps.h"
88 #include "interface.h"
89 #include "util.h"
90 #include "wx.h"
91 #include "forked_getaddrinfo.h"
92 #include "x_spider.h"
93 #include "db_gis.h"
94 #include "gps.h"
95 
96 #ifdef HAVE_LIBAX25
97   #include <netax25/ax25.h>
98   #include <netrose/rose.h>
99   #include <netax25/axlib.h>
100   #include <netax25/axconfig.h>
101 #endif  // HAVE_LIBAX25
102 
103 // Must be last include file
104 #include "leak_detection.h"
105 
106 
107 
108 #ifndef SIGRET
109   #define SIGRET  void
110 #endif  // SIGRET
111 
112 // Older versions of glibc <= 2.3.0 and <= OS X 10.5 do not have this
113 // constant defined
114 #ifndef AI_NUMERICSERV
115   #define AI_NUMERICSERV 0
116 #endif
117 
118 //extern pid_t getpgid(pid_t pid);
119 extern void port_write_binary(int port, unsigned char *data, int length);
120 
121 
122 iodevices dtype[MAX_IFACE_DEVICE_TYPES]; // device names
123 
124 iface port_data[MAX_IFACE_DEVICES];     // shared port data
125 
126 int port_id[MAX_IFACE_DEVICES];         // shared port id data
127 
128 xastir_mutex port_data_lock;            // Protects the port_data[] array of structs
129 xastir_mutex data_lock;                 // Protects incoming_data_queue
130 xastir_mutex output_data_lock;          // Protects interface.c:channel_data() function only
131 xastir_mutex connect_lock;              // Protects port_data[].thread_status and port_data[].connect_status
132 
133 void port_write_string(int port, char *data);
134 
135 int ax25_ports_loaded = 0;
136 
137 
138 // Incoming data queue
139 typedef struct _incoming_data_record
140 {
141   int length;   // Used for binary strings such as KISS
142   int port;
143   unsigned char data[MAX_LINE_SIZE];
144 } incoming_data_record;
145 #define MAX_INPUT_QUEUE 1000
146 static incoming_data_record incoming_data_queue[MAX_INPUT_QUEUE];
147 unsigned char incoming_data_copy[MAX_LINE_SIZE];            // Used for debug
148 unsigned char incoming_data_copy_previous[MAX_LINE_SIZE];   // Used for debug
149 
150 // interface wait time out
151 int NETWORK_WAITTIME;
152 
153 
154 
155 
156 
157 // Read/write pointers for the circular input queue
158 static int incoming_read_ptr = 0;
159 static int incoming_write_ptr = 0;
160 static int queue_depth = 0;
161 static int push_count = 0;
162 static int pop_count = 0;
163 
164 
165 
166 
167 
168 // Fetch a record from the circular queue.
169 // Returns 0 if no records available
170 // Else returns length of string, data_string and port
171 // data_string variable should be of size MAX_LINE_SIZE
172 //
pop_incoming_data(unsigned char * data_string,int * port)173 int pop_incoming_data(unsigned char *data_string, int *port)
174 {
175   int length;
176   int jj;
177 
178   if (begin_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0)
179   {
180     fprintf(stderr,"data_lock\n");
181   }
182 
183   // Check for queue empty
184   if (incoming_read_ptr == incoming_write_ptr)
185   {
186     // Yep, it's empty
187 
188     queue_depth = 0;
189 
190     if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0)
191     {
192       fprintf(stderr,"data_lock\n");
193     }
194     return(0);
195   }
196 
197   // Bump the read pointer
198   incoming_read_ptr = (incoming_read_ptr + 1) % MAX_INPUT_QUEUE;
199 
200   *port = incoming_data_queue[incoming_read_ptr].port;
201 
202   length = incoming_data_queue[incoming_read_ptr].length;
203 
204   // Yes, this is a string, but it may have zeros embedded.  We can't
205   // use string manipulation functions because of that:
206   for (jj = 0; jj < length; jj++)
207   {
208     data_string[jj] = incoming_data_queue[incoming_read_ptr].data[jj];
209   }
210 
211   // Add terminator, just in case
212   data_string[length+1] = '\0';
213 
214   queue_depth--;
215   pop_count++;
216 
217   if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0)
218   {
219     fprintf(stderr,"data_lock\n");
220   }
221 
222   return(length);
223 }
224 
225 
226 
227 
228 
229 // Add one record to the circular queue.  Returns 1 if queue is
230 // full, 0 if successful.
231 //
push_incoming_data(unsigned char * data_string,int length,int port)232 int push_incoming_data(unsigned char *data_string, int length, int port)
233 {
234   int next_write_ptr = (incoming_write_ptr + 1) % MAX_INPUT_QUEUE;
235   int jj;
236 
237 
238   if (begin_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0)
239   {
240     fprintf(stderr,"data_lock\n");
241   }
242 
243   // Check whether queue is full
244   if (incoming_read_ptr == next_write_ptr)
245   {
246     // Yep, it's full!
247 
248     if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0)
249     {
250       fprintf(stderr,"data_lock\n");
251     }
252     return(1);
253   }
254 
255 
256   // Advance the write pointer
257   incoming_write_ptr = next_write_ptr;
258 
259   incoming_data_queue[incoming_write_ptr].length = length;
260 
261   incoming_data_queue[incoming_write_ptr].port = port;
262 
263   // Binary safe copy in case there are embedded zeros
264   for (jj = 0; jj < length; jj++)
265   {
266     incoming_data_queue[incoming_write_ptr].data[jj] = data_string[jj];
267   }
268 
269   queue_depth++;
270   push_count++;
271 
272   if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0)
273   {
274     fprintf(stderr,"data_lock\n");
275   }
276 
277   return(0);
278 }
279 
280 
281 
282 
283 
284 // Returns 1 if a local interface, 0 otherwise
285 //
is_local_interface(int port)286 int is_local_interface(int port)
287 {
288 
289   switch (port_data[port].device_type)
290   {
291 
292     case DEVICE_SERIAL_TNC:
293     case DEVICE_SERIAL_TNC_HSP_GPS:
294     case DEVICE_SERIAL_GPS:
295     case DEVICE_SERIAL_WX:
296     case DEVICE_AX25_TNC:
297     case DEVICE_SERIAL_TNC_AUX_GPS:
298     case DEVICE_SERIAL_KISS_TNC:
299     case DEVICE_SERIAL_MKISS_TNC:
300       return(1);  // Found a local interface
301       break;
302 
303     // Could be port -1 which signifies a spider port or port
304     // -99 which signifies "All Ports" and is used for
305     // transmitting out all ports at once.
306     default:
307       return(0);  // Unknown or network interface
308       break;
309   }
310 }
311 
312 
313 
314 
315 
316 // Returns 1 if a network interface, 0 otherwise
317 //
is_network_interface(int port)318 int is_network_interface(int port)
319 {
320 
321   switch (port_data[port].device_type)
322   {
323 
324     case DEVICE_NET_STREAM:
325     case DEVICE_NET_GPSD:
326     case DEVICE_NET_WX:
327     case DEVICE_NET_DATABASE:
328     case DEVICE_NET_AGWPE:
329       return(1);  // Found a network interface
330       break;
331 
332     // Could be port -1 which signifies a spider port or port
333     // -99 which signifies "All Ports" and is used for
334     // transmitting out all ports at once.
335     default:
336       return(0);  // Unknown or local interface
337       break;
338   }
339 }
340 
341 
342 
343 
344 
345 
346 // Create a packet and send to AGWPE for transmission.
347 // Format is as follows:
348 //
349 //  RadioPort     4 bytes (0-3)
350 //  DataType      4 bytes (4-7)
351 //  FromCall     10 bytes (8-17)
352 //  ToCall       10 bytes (18-27)
353 //  DataLength    4 bytes (28-31)
354 //  UserField     4 bytes (32-35)
355 //  Data         DataLength bytes (36-?)
356 //
357 // Callsigns are null-terminated at end of string, but callsign
358 // field width is specified to be 10 bytes in all cases.
359 //
360 // Path is split up into the various ViaCalls.  Path may also be a
361 // NULL pointer.
362 //
363 // If type != '\0', then we'll create the specified type of packet.
364 //
365 // Else if Path is not empty, we'll use packet format "V" with
366 // Viacalls prepended to the Data portion of the packet, 10 chars
367 // per digi, with the number of digis as the first character.  The
368 // packet data then follows after the last via callsign.
369 //
370 // Else if no Path, then put the Data directly into the Data
371 // field and use "M" format packets.
372 //
373 // We currently use the base portion of my_callsign as the username
374 // portion of the AGWPE login.  This must be upper-case when you're
375 // setting up the account in AGWPE, as that's what we send to
376 // authenticate.
377 //
send_agwpe_packet(int xastir_interface,int RadioPort,unsigned char type,unsigned char * FromCall,unsigned char * ToCall,unsigned char * Path,unsigned char * Data,int length)378 void send_agwpe_packet(int xastir_interface,// Xastir interface port
379                        int RadioPort,       // AGWPE RadioPort
380                        unsigned char type,
381                        unsigned char *FromCall,
382                        unsigned char *ToCall,
383                        unsigned char *Path,
384                        unsigned char *Data,
385                        int length)
386 {
387   int ii;
388 #define agwpe_header_size 36
389   unsigned char output_string[512+agwpe_header_size];
390   unsigned char path_string[200];
391   int full_length;
392   int data_length;
393 
394 
395   // Check size of data
396   if (length > 512)
397   {
398     return;
399   }
400 
401   // Clear the output_string (set to binary zeroes)
402   for (ii = 0; ii < (int)sizeof(output_string); ii++)
403   {
404     output_string[ii] = '\0';
405   }
406 
407   if (type != 'P')
408   {
409     // Write the port number into the frame.  Note that AGWPE
410     // uses 1 for the first port in its GUI, but the programming
411     // interface starts at 0.
412     output_string[0] = (unsigned char)RadioPort;
413 
414     if (FromCall)   // Write the FromCall string into the frame
415       xastir_snprintf((char *)&output_string[8],
416                       sizeof(output_string) - 8,
417                       "%s",
418                       FromCall);
419 
420     if (ToCall) // Write the ToCall string into the frame
421       xastir_snprintf((char *)&output_string[18],
422                       sizeof(output_string) - 18,
423                       "%s",
424                       ToCall);
425   }
426 
427   if ( (type != '\0') && (type != 'P') )
428   {
429     // Type was specified, not a data frame or login frame
430 
431     // Write the type character into the frame
432     output_string[4] = type;
433 
434     // Send the packet to AGWPE
435     port_write_binary(xastir_interface,
436                       output_string,
437                       agwpe_header_size);
438   }
439 
440   else if (Path == NULL)   // No ViaCalls, Data or login packet
441   {
442 
443     if (type == 'P')
444     {
445       // Login/Password frame
446       char callsign_base[15];
447       int new_length;
448 
449 
450       // Write the type character into the frame
451       output_string[4] = type;
452 
453       // Compute the callsign base string
454       // (callsign minus SSID)
455       xastir_snprintf(callsign_base,
456                       sizeof(callsign_base),
457                       "%s",
458                       my_callsign);
459       // Change '-' into end of string
460       strtok(callsign_base, "-");
461 
462       // Length = length of each string plus the two
463       // terminating zeroes.
464       //new_length = strlen(callsign_base) + length + 2;
465       new_length = 255+255;
466 
467       output_string[28] = (unsigned char)(new_length % 256);
468       output_string[29] = (unsigned char)((new_length >> 8) % 256);
469 
470       // Write login/password out as 255-byte strings each
471 
472       // Put the login string into the buffer
473       xastir_snprintf((char *)&output_string[agwpe_header_size],
474                       sizeof(output_string) - agwpe_header_size,
475                       "%s",
476                       callsign_base);
477 
478       // Put the password string into the buffer
479       xastir_snprintf((char *)&output_string[agwpe_header_size+255],
480                       sizeof(output_string) - agwpe_header_size - 255,
481                       "%s",
482                       Data);
483 
484       // Send the packet to AGWPE
485       port_write_binary(xastir_interface,
486                         output_string,
487                         255+255+agwpe_header_size);
488     }
489     else    // Data frame
490     {
491       // Write the type character into the frame
492       output_string[4] = 'M'; // Unproto, no via calls
493 
494       // Write the PID type into the frame
495       output_string[6] = 0xF0;    // UI Frame
496 
497       output_string[28] = (unsigned char)(length % 256);
498       output_string[29] = (unsigned char)((length >> 8) % 256);
499 
500       // Copy Data onto the end of the string.  This one
501       // doesn't have to be null-terminated, so strncpy() is
502       // ok to use here.  strncpy stops at the first null byte
503       // though.  Proper for a binary output routine?  NOPE!
504       strncpy((char *)(&output_string[agwpe_header_size]),(char *)Data, length);
505 
506       full_length = length + agwpe_header_size;
507 
508       // Send the packet to AGWPE
509       port_write_binary(xastir_interface,
510                         output_string,
511                         full_length);
512 
513     }
514   }
515 
516   else    // We have ViaCalls.  Data packet.
517   {
518     char *ViaCall[10];
519 
520     // Doesn't need to be null-terminated, so strncpy is ok to
521     // use here.  strncpy stops at the first null byte though.
522     // Proper for a binary output routine?  NOPE!
523     strncpy((char *)path_string, (char *)Path, sizeof(path_string));
524 
525     // Convert path_string to upper-case
526     to_upper((char *)path_string);
527 
528     split_string((char *)path_string, ViaCall, 10, ',');
529 
530     // Write the type character into the frame
531     output_string[4] = 'V'; // Unproto, via calls present
532 
533     // Write the PID type into the frame
534     output_string[6] = 0xF0;    // UI Frame
535 
536     // Write the number of ViaCalls into the first byte
537     if (ViaCall[7])
538     {
539       output_string[agwpe_header_size] = 0x08;
540     }
541     else if (ViaCall[6])
542     {
543       output_string[agwpe_header_size] = 0x07;
544     }
545     else if (ViaCall[5])
546     {
547       output_string[agwpe_header_size] = 0x06;
548     }
549     else if (ViaCall[4])
550     {
551       output_string[agwpe_header_size] = 0x05;
552     }
553     else if (ViaCall[3])
554     {
555       output_string[agwpe_header_size] = 0x04;
556     }
557     else if (ViaCall[2])
558     {
559       output_string[agwpe_header_size] = 0x03;
560     }
561     else if (ViaCall[1])
562     {
563       output_string[agwpe_header_size] = 0x02;
564     }
565     else
566     {
567       output_string[agwpe_header_size] = 0x01;
568     }
569 
570     // Write the ViaCalls into the Data field
571     switch (output_string[agwpe_header_size])
572     {
573       case 8:
574         if (ViaCall[7])
575         {
576           strncpy((char *)(&output_string[agwpe_header_size+1+70]), ViaCall[7], 10);
577         }
578         else
579         {
580           return;
581         }
582       /* Falls through. */
583       case 7:
584         if (ViaCall[6])
585         {
586           strncpy((char *)(&output_string[agwpe_header_size+1+60]), ViaCall[6], 10);
587         }
588         else
589         {
590           return;
591         }
592       /* Falls through. */
593       case 6:
594         if (ViaCall[5])
595         {
596           strncpy((char *)(&output_string[agwpe_header_size+1+50]), ViaCall[5], 10);
597         }
598         else
599         {
600           return;
601         }
602       /* Falls through. */
603       case 5:
604         if (ViaCall[4])
605         {
606           strncpy((char *)(&output_string[agwpe_header_size+1+40]), ViaCall[4], 10);
607         }
608         else
609         {
610           return;
611         }
612       /* Falls through. */
613       case 4:
614         if (ViaCall[3])
615         {
616           strncpy((char *)(&output_string[agwpe_header_size+1+30]), ViaCall[3], 10);
617         }
618         else
619         {
620           return;
621         }
622       /* Falls through. */
623       case 3:
624         if (ViaCall[2])
625         {
626           strncpy((char *)(&output_string[agwpe_header_size+1+20]), ViaCall[2], 10);
627         }
628         else
629         {
630           return;
631         }
632       /* Falls through. */
633       case 2:
634         if (ViaCall[1])
635         {
636           strncpy((char *)(&output_string[agwpe_header_size+1+10]), ViaCall[1], 10);
637         }
638         else
639         {
640           return;
641         }
642       /* Falls through. */
643       case 1:
644       default:
645         if (ViaCall[0])
646         {
647           strncpy((char *)(&output_string[agwpe_header_size+1+0]),  ViaCall[0], 10);
648         }
649         else
650         {
651           return;
652         }
653         break;
654     }
655 
656     // Write the Data onto the end.
657     // Doesn't need to be null-terminated, so strncpy is ok to
658     // use here.  strncpy stops at the first null byte though.
659     // Proper for a binary output routine?
660     strncpy((char *)(&output_string[((int)(output_string[agwpe_header_size]) * 10) + agwpe_header_size + 1]),
661             (char *)Data,
662             length);
663 
664     //Fill in the data length field.  We're assuming the total
665     //is less than 512 + 37.
666     data_length = length + ((int)(output_string[agwpe_header_size]) * 10) + 1;
667 
668     if ( data_length > 512 )
669     {
670       return;
671     }
672 
673     output_string[28] = (unsigned char)(data_length % 256);
674     output_string[29] = (unsigned char)((data_length >> 8) % 256);
675 
676     full_length = data_length + agwpe_header_size;
677 
678     // Send the packet to AGWPE
679     port_write_binary(xastir_interface,
680                       output_string,
681                       full_length);
682 
683 
684   }
685 }
686 
687 
688 
689 
690 
691 /*
692 // Here is a "monitor" UI packet
693 //
694 Total Length = 150
695 HEX:00 00 00 00 55 00 00 00 4b 4b 31 57 00 ed 12 00 96 ed 41 50 54
696 57 30 31 00 00 00 00 72 00 00 00 00 00 00 00 20 31 3a 46 6d 20 4b 4b
697 31 57 20 54 6f 20 41 50 54 57 30 31 20 56 69 61 20 57 49 44 45 33 20
698 3c 55 49 20 70 69 64 3d 46 30 20 4c 65 6e 3d 35 30 20 3e 5b 31 30 3a
699 34 33 3a 34 33 5d 0d 5f 30 38 30 36 31 30 33 39 63 33 35 39 73 30 30
700 30 67 30 30 30 74 30 36 32 72 30 30 30 70 30 30 33 50 30 39 36 68 30
701 30 62 31 30 30 39 33 74 55 32 6b 0d 0d 00
702 ASC:....U...KK1W......APTW01....r....... 1:Fm KK1W To APTW01 Via WIDE3 <UI pid=F0 Len=50 >[10:43:43]._08061039c359s000g000t062r000p003P096h00b10093tU2k...
703 */
704 
705 /*
706 // And here are some "raw" UI packets
707 //
708 AGWPE: Got raw frame packet
709 3:2e
710 Bad KISS packet.  Dropping it.
711 Total Length = 135
712 HEX:00 00 00 00 4b 00 00 00 4e 32 4c 42 54 2d 37 00 01 00 41 50 58
713 31 33 33 00 00 00 00 63 00 00 00 00 00 00 00
714 
715 c0 82 a0 b0 62 66 66 60
716 9c 64 98 84 a8 40 6e 96 82 64 a2 b2 8a f4 ae 92 88 8a 40 40 61 03 f0
717 40 30 37 30 30 32 37 7a 34 32 33 39 2e 30 34 4e 5c 30 37 33 34 38 2e
718 31 30 57 5f 30 30 30 2f 30 30 30 67 30 30 30 74 30 36 34 72 30 30 30
719 50 30 30 30 70 30 30 30 68 35 33 62 31 30 31 32 37 58 55 32 6b 0d
720 ASC:....K...N2LBT-7...APX133....c...........bff`.d...@n..d........@@a..@070027z4239.04N\07348.10W_000/000g000t064r000P000p000h53b10127XU2k.
721 AGWPE: Got raw frame packet
722 3:23
723 Bad KISS packet.  Dropping it.
724 Total Length = 104
725 HEX:00 00 00 00 4b 00 00 00 4e 31 45 44 5a 2d 37 00 01 00 54 52 31
726 55 37 58 00 00 00 00 44 00 00 00 00 00 00 00
727 
728 c0 a8 a4 62 aa 6e b0 60
729 9c 62 8a 88 b4 40 ee 96 82 62 a2 8c 8a fe ae 62 a8 9e 9a 40 fe 96 82
730 64 a2 b2 8a f5 03 f0 60 64 2a 39 6c 23 22 3e 2f 3e 22 35 6b 7d 6e 31
731 65 64 7a 40 61 6d 73 61 74 2e 6f 72 67 0d
732 ASC:....K...N1EDZ-7...TR1U7X....D..........b.n.`.b...@...b.....b...@...d......`d*9l#">/>"5k}n1edz@amsat.org.
733 AGWPE: Got raw frame packet
734 3:2e
735 Bad KISS packet.  Dropping it.
736 Total Length = 103
737 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54
738 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00
739 
740 c0 82 a0 a8 66 62 62 60
741 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 ae 92 88 8a 40 40 61 03 f0
742 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38
743 2f 30 32 30 2f 41 3d 30 30 30 34 38 35
744 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d........@@a..!4319.79N/07340.87W>268/020/A=000485
745 AGWPE: Got raw frame packet
746 3:74
747 Bad KISS packet.  Dropping it.
748 Total Length = 82
749 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54
750 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00
751 
752 c0 82 a0 a8 66 62 62 60
753 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 ae 82 64 aa 9a b0 e5 03 f0
754 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74
755 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net
756 AGWPE: Got raw frame packet
757 3:2e
758 Bad KISS packet.  Dropping it.
759 Total Length = 103
760 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54
761 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00
762 
763 c0 82 a0 a8 66 62 62 60
764 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0
765 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38
766 2f 30 32 30 2f 41 3d 30 30 30 34 38 35
767 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r.d...@...d......!4319.79N/07340.87W>268/020/A=000485
768 AGWPE: Got raw frame packet
769 3:74
770 Bad KISS packet.  Dropping it.
771 Total Length = 82
772 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54
773 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00
774 
775 c0 82 a0 a8 66 62 62 60
776 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0
777 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74
778 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net
779 AGWPE: Got raw frame packet
780 3:2e
781 Bad KISS packet.  Dropping it.
782 Total Length = 103
783 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54
784 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00
785 
786 c0 82 a0 a8 66 62 62 60
787 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 96 82 64 a2 b2 8a f5 03 f0
788 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38
789 2f 30 32 30 2f 41 3d 30 30 30 34 38 35
790 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d......d......!4319.79N/07340.87W>268/020/A=000485
791 */
792 
793 
794 // Parse an AGWPE header.  Create a TAPR-2 style header out of the
795 // data for feeding into the Xastir parsing code.  Input format is
796 // as follows:
797 //
798 //  RadioPort     4 bytes (0-3)
799 //  DataType      4 bytes (4-7)
800 //  FromCall     10 bytes (8-17)
801 //  ToCall       10 bytes (18-27)
802 //  DataLength    4 bytes (28-31)
803 //  UserField     4 bytes (32-35)
804 //  Data         xx bytes (36-??)
805 //
806 // Callsigns are null-terminated at end of string, but field width
807 // is specified to be 10 bytes in all cases.
808 //
809 // output_string variable should be quite long, perhaps 1000
810 // characters.
811 //
812 // Someday it would be nice to turn on raw packet format in AGWPE
813 // which gives us the AX.25 packet format directly.  We should be
814 // able to use our normal KISS decoding functions to parse those
815 // types of packets, instead of the mess we have below which is
816 // parsing a few things out of the header, a few things out of the
817 // text that AGWPE puts after the header, and then snagging the info
818 // field of the packet from the tail-end.
819 //
parse_agwpe_packet(unsigned char * input_string,int output_string_length,unsigned char * output_string,int * new_length)820 unsigned char *parse_agwpe_packet(unsigned char *input_string,
821                                   int output_string_length,
822                                   unsigned char *output_string,
823                                   int *new_length)
824 {
825   int ii, jj, kk;
826   char *info_ptr;
827   char *via_ptr;
828   char temp_str[512];
829   int special_debug = 0;
830   int data_length;
831 
832 
833   // Fetch the length of the data portion of the packet
834   data_length = (unsigned char)(input_string[31]);
835   data_length = (data_length << 8) + (unsigned char)(input_string[30]);
836   data_length = (data_length << 8) + (unsigned char)(input_string[29]);
837   data_length = (data_length << 8) + (unsigned char)(input_string[28]);
838 
839   // Implementing some special debugging output for the case of
840   // third-party NWS messages, which so far haven't been parsed
841   // properly by this function.
842   //
843   // Check for NWS string past the header part of the AGWPE
844   // packet.
845   //
846 
847   // Make sure we have a terminating '\0' at the end.
848   // Note that this doesn't help for binary packets (like OpenTrac),
849   // but doesn't really hurt either.
850   input_string[38+data_length] = '\0';
851 
852 
853   // Check what sort of AGWPE packet it is.
854   switch (input_string[4])
855   {
856 
857     case 'R':
858       if (data_length == 8)
859       {
860         fprintf(stderr,
861                 "\nConnected to AGWPE server, version: %d.%d\n",
862                 (input_string[37] << 8) + input_string[36],
863                 (input_string[41] << 8) + input_string[40]);
864       }
865       return(NULL);   // All done!
866       break;
867 
868     case 'G':
869       // Print out the data, changing all ';' characters to
870       // <CR> and a bunch of spaces to format it nicely.
871       fprintf(stderr, "    Port Info, total ports = ");
872       ii = 36;
873       while (ii < data_length + 36 && input_string[ii] != '\0')
874       {
875         if (input_string[ii] == ';')
876         {
877           fprintf(stderr, "\n    ");
878         }
879         else
880         {
881           fprintf(stderr, "%c", input_string[ii]);
882         }
883         ii++;
884       }
885       fprintf(stderr,"\n");
886       return(NULL);   // All done!
887       break;
888 
889     case 'g':
890       return(NULL);   // All done!
891       break;
892 
893     case 'X':
894       return(NULL);   // All done!
895       break;
896 
897     case 'y':
898       return(NULL);   // All done!
899       break;
900 
901     case 'Y':
902       return(NULL);   // All done!
903       break;
904 
905     case 'H':
906       return(NULL);   // All done!
907       break;
908 
909     case 'C':
910       return(NULL);   // All done!
911       break;
912 
913     case 'v':
914       return(NULL);   // All done!
915       break;
916 
917     case 'c':
918       return(NULL);   // All done!
919       break;
920 
921     case 'D':
922       return(NULL);   // All done!
923       break;
924 
925     case 'd':
926       return(NULL);   // All done!
927       break;
928 
929     case 'U':
930       // We can decode this one ok in the below code (after
931       // this switch statement), but we no longer use
932       // "monitor" mode packets in AGWPE, switching to the
933       // "raw" mode instead.
934       return(NULL);   // All done!
935       break;
936 
937     case 'I':
938       return(NULL);   // All done!
939       break;
940 
941     case 'S':
942       return(NULL);   // All done!
943       break;
944 
945     case 'T':
946       // We should decode this one ok in the below code (after
947       // this switch statement), but we no longer use
948       // "monitor" mode packets in AGWPE, switching to the
949       // "raw" mode instead.
950       return(NULL);   // All done!
951       break;
952 
953     case 'K':
954       // Code here processes the packet for handing to our
955       // KISS decoding routines.  Chop off the header, add
956       // anything to the beginning/end that we need, then send
957       // it to decode_ax25_header().
958 
959       // Try to decode header and checksum.  If bad, break,
960       // else continue through to ASCII logging & decode
961       // routines.  We skip the first byte as it's not part of
962       // the AX.25 packet.
963       //
964       // Note that the packet length often increases here in
965       // decode_ax25_header, as we add '*' characters and such
966       // to the header as it's decoded.
967 
968       // This string already has a terminator on the end,
969       // added by the code in port_read().  If we didn't have
970       // one here, we could end up with portions of strings
971       // concatenated on the end of our string by the time
972       // we're done processing the data here.
973       //
974       //            input_string[data_length+36] = '\0';
975 
976 
977       // WE7U:
978       // We may need to extend input_string by a few characters before it
979       // is fed to us.  Something like max_callsigns * 3 or 4 characters,
980       // to account for '*' and SSID characters that we might add.  This
981       // keeps the string from getting truncated as we add bytes to the
982       // header in decode_ax25_header.
983 
984 
985       if ( !decode_ax25_header( (unsigned char *)&input_string[37], &data_length ) )
986       {
987         //                int zz;
988 
989         // Had a problem decoding it.  Drop it on the floor.
990         fprintf(stderr, "AGWPE: Bad KISS packet.  Dropping it.\n");
991 
992         special_debug++;
993         //                for (zz = 0; zz < data_length; zz++) {
994         //                    fprintf(stderr, "%02x ", input_string[zz+36]);
995         //                }
996         //                fprintf(stderr,"\n");
997 
998         return(NULL);
999       }
1000 
1001       // Good header.  Compute the new length, again skipping
1002       // the first byte.
1003       data_length = strlen((const char *)&input_string[37]);
1004 
1005       // The above strlen() requires it to be printable ascii in the KISS
1006       // packet, so won't work for OpenTrac protocol or other binary
1007       // protocols.  The decode_ax25_header() function also looks for
1008       // PID=0xF0, which again won't work for OpenTrac.  It would be
1009       // better to have the decode_ax25_header routine return the new
1010       // length of the packet so that decoding of binary packets is still
1011       // possible.
1012 
1013       // Check for OpenTrac packets.  If found, dump them into
1014       // OpenTrac-specific decode and skip the other decode below.  Must
1015       // tweak the above stuff to allow binary-format packets to get
1016       // through to this point.
1017 
1018       // Do more stuff with the packet here.  The actual
1019       // packet itself starts at offset 37.  We can end up
1020       // with 0x0d, 0x0d 0x0d, or 0x0d 0x00 0x0d on the end of
1021       // it (or none of the above).  Best method should be to
1022       // just search for any 0x0d's or 0x0a's starting at the
1023       // beginning of the string and overwrite them with
1024       // 0x00's.  That's what we do here.
1025       //
1026       for (ii = 0; ii < data_length; ii++)
1027       {
1028         if (input_string[ii+37] == 0x0d
1029             || input_string[ii+37] == 0x0a)
1030         {
1031           input_string[ii+37] = '\0';
1032         }
1033       }
1034 
1035       // Compute data_length again.
1036       data_length = strlen((const char *)&input_string[37]);
1037 
1038       // Send the processed string back for decoding
1039       xastir_snprintf((char *)output_string,
1040                       output_string_length,
1041                       "%s",
1042                       &input_string[37]);
1043 
1044       // Send back the new length.
1045       *new_length = data_length;
1046 
1047       return(output_string);
1048       break;
1049 
1050     default:
1051       fprintf(stderr,"AGWPE: Got unrecognized '%c' packet\n",input_string[4]);
1052       return(NULL);   // All done!
1053       break;
1054   }
1055 
1056 
1057   // NOTE:  All of the code below gets used in "monitor" mode, which
1058   // we no longer use.  We might keep this code around for a bit and
1059   // then delete it, as we've probably switched to "raw" mode for
1060   // good.  "raw" mode allows us to use our KISS processing routines,
1061   // plus allows us to support digipeating and OpenTrac (binary)
1062   // protocol in the future.
1063 
1064 
1065   if (special_debug)
1066   {
1067     // Dump the hex & ascii representation of the whole packet
1068 
1069     kk = data_length + 36; // Add the header length
1070     fprintf(stderr, "Total Length = %d\n", kk);
1071 
1072     fprintf(stderr, "HEX:");
1073     for (ii = 0; ii < kk; ii++)
1074     {
1075       fprintf(stderr, "%02x ", input_string[ii]);
1076     }
1077     fprintf(stderr, "\n");
1078 
1079     fprintf(stderr, "ASC:");
1080     for (ii = 0; ii < kk; ii++)
1081     {
1082       if (input_string[ii] < ' ' || input_string[ii] > '~')
1083       {
1084         fprintf(stderr, ".");
1085       }
1086       else
1087       {
1088         fprintf(stderr, "%c", input_string[ii]);
1089       }
1090     }
1091     fprintf(stderr, "\n");
1092   }
1093 
1094   // Clear the output_string (set to binary zeroes)
1095   for (ii = 0; ii < output_string_length; ii++)
1096   {
1097     output_string[ii] = '\0';
1098   }
1099 
1100   jj = 0;
1101 
1102   // Copy the source callsign
1103   ii = 8;
1104   while (input_string[ii] != '\0')
1105   {
1106     output_string[jj++] = input_string[ii++];
1107   }
1108 
1109   // Add a '>' character
1110   output_string[jj++] = '>';
1111 
1112   // Copy the destination callsign
1113   ii = 18;
1114   while (input_string[ii] != '\0')
1115   {
1116     output_string[jj++] = input_string[ii++];
1117   }
1118 
1119   // Search for "]" (0x5d) which is the end of the header string,
1120   // beginning of the AX.25 information field.
1121   info_ptr = strstr((const char *)&input_string[36], "]");
1122 
1123   // If not found, we can't process anymore
1124   if (!info_ptr)
1125   {
1126     output_string[0] = '\0';
1127     new_length = 0;
1128     return(NULL);
1129   }
1130 
1131   // Copy the first part of the string into a variable.  We'll
1132   // look for Via calls in this string, if present.
1133   ii = 36;
1134   temp_str[0] = '\0';
1135 
1136   while (input_string[ii] != ']')
1137   {
1138     strncat(temp_str, (char *)(&input_string[ii++]), 1);
1139   }
1140 
1141   // Make sure that the protocol ID is "F0".  If not, return.
1142   if (strstr(temp_str, "pid=F0") == NULL)
1143   {
1144     char *pid_ptr;
1145 
1146     // Look for the "pid=" string and print out what we can
1147     // figure out about the protocol ID.
1148     pid_ptr = strstr(temp_str, "pid=");
1149     if (pid_ptr)
1150     {
1151       pid_ptr +=4;
1152       fprintf(stderr,
1153               "parse_agwpe_packet: Non-APRS protocol was seen: PID=%2s.  Dropping the packet.\n",
1154               pid_ptr);
1155     }
1156     else
1157     {
1158       fprintf(stderr,
1159               "parse_agwpe_packet: Non-APRS protocol was seen.  Dropping the packet.\n");
1160     }
1161     output_string[0] = '\0';
1162     new_length = 0;
1163     return(NULL);
1164   }
1165 
1166   // Search for "Via" in temp_str
1167   via_ptr = strstr(temp_str, "Via");
1168 
1169   if (via_ptr)
1170   {
1171     // Found some Via calls.  Copy them into our output string.
1172 
1173     // Add a comma first
1174     output_string[jj++] = ',';
1175 
1176     // Skip past "Via " portion of string
1177     via_ptr += 4;
1178 
1179     // Copy the string across until we hit a space
1180     while (via_ptr[0] != ' ')
1181     {
1182       output_string[jj++] = via_ptr[0];
1183       via_ptr++;
1184     }
1185   }
1186 
1187   // Add a ':' character
1188   output_string[jj++] = ':';
1189 
1190   // Move the pointer past the "]<CR>" to the real info part of the
1191   // packet.
1192   info_ptr++;
1193   info_ptr++;
1194 
1195   // Copy the info field to the output string
1196   while (info_ptr[0] != '\0')
1197   {
1198     strncat((char *)output_string, &info_ptr[0], 1);
1199     info_ptr++;
1200   }
1201 
1202   // We end up with 0x0d characters on the end.  Get rid of them.
1203   // The strtok() function will overwrite the first one found with
1204   // a '\0' character.
1205   (void)strtok((char *)output_string, "\n");
1206   (void)strtok((char *)output_string, "\r");
1207 
1208   *new_length = strlen((const char *)output_string);
1209 
1210   if (special_debug)
1211   {
1212     // Print out the resulting string
1213     fprintf(stderr,"AGWPE RX: %s\n", output_string);
1214     fprintf(stderr,"new_length: %d\n",*new_length);
1215     for (ii = 0; ii < (int)strlen((const char *)output_string); ii++)
1216     {
1217       fprintf(stderr,"%02x ",output_string[ii]);
1218     }
1219     fprintf(stderr,"\n");
1220   }
1221 
1222   return(output_string);
1223 }
1224 
1225 /*
1226   Found complete AGWPE packet, 93 bytes total in frame:
1227   00 00 00 00
1228   55 00 00 00                     'U' Packet
1229   57 45 37 55 2d 33 00 00 ff ff   WE7U-3
1230   41 50 52 53 00 20 ec e9 6c 00   APRS
1231   39 00 00 00                     Length
1232   00 00 00 00
1233 
1234   20 31                           .1 (36-37)
1235   3a 46 6d 20                     :Fm (38-41)
1236   57 45 37 55 2d 33               WE7U-3 (42-space)
1237   20 54 6f                        .To
1238   20 41 50 52 53                  .APRS
1239   20 3c 55 49                     .<UI
1240   20 70 69 64 3d 46 30            .pid=F0
1241   20 4c 65 6e 3d 34               .Len=4
1242   20 3e 5b 32 33 3a 31 33 3a 32 30 5d 0d  >[23:13:20].
1243   54 65 73 74 0d 0d 00            Test<CR><CR>.
1244   ....U...WE7U-3....APRS. ..l.9....... 1:Fm WE7U-3 To APRS <UI pid=F0 Len=4 >[23:13:20].Test...
1245 
1246   1:Fm WE7U-3 To APRS Via RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1 <UI pid=F0 Len=26 >[23:51:46].Testing this darned thing!...
1247 */
1248 
1249 
1250 
1251 
1252 
1253 //****************************************************************
1254 // get device name only (the portion at the end of the full path)
1255 // device_name current full name of device
1256 //****************************************************************
1257 
get_device_name_only(char * device_name)1258 char *get_device_name_only(char *device_name)
1259 {
1260   int i,len,done;
1261 
1262   if (device_name == NULL)
1263   {
1264     return(NULL);
1265   }
1266 
1267   done = 0;
1268   len = (int)strlen(device_name);
1269   for(i = len; i > 0 && !done; i--)
1270   {
1271     if(device_name[i] == '/')
1272     {
1273       device_name += (i+1);
1274       done = 1;
1275     }
1276   }
1277   return(device_name);
1278 }
1279 
1280 
1281 
1282 
1283 
1284 //***********************************************************
1285 // Get Open Device
1286 //
1287 // if device is available this will return the port #
1288 // otherwise a -1 will be returned in error.
1289 //***********************************************************
get_open_device(void)1290 int get_open_device(void)
1291 {
1292   int i, found;
1293 
1294   begin_critical_section(&devices_lock, "interface.c:get_open_device" );
1295 
1296   found = -1;
1297   for(i = 0; i < MAX_IFACE_DEVICES && found == -1; i++)
1298   {
1299     if (devices[i].device_type == DEVICE_NONE)
1300     {
1301       found = i;
1302       break;
1303     }
1304   }
1305 
1306   end_critical_section(&devices_lock, "interface.c:get_open_device" );
1307 
1308   if (found == -1)
1309   {
1310     popup_message(langcode("POPEM00004"),langcode("POPEM00017"));
1311   }
1312 
1313   return(found);
1314 }
1315 
1316 
1317 
1318 
1319 
1320 //***********************************************************
1321 // Get Device Status
1322 //
1323 // this will return the device status for the port specified
1324 //***********************************************************
get_device_status(int port)1325 int get_device_status(int port)
1326 {
1327   int stat;
1328 
1329   if (begin_critical_section(&port_data_lock, "interface.c:get_device_status(1)" ) > 0)
1330   {
1331     fprintf(stderr,"port_data_lock, Port = %d\n", port);
1332   }
1333 
1334   stat = port_data[port].status;
1335 
1336   if (end_critical_section(&port_data_lock, "interface.c:get_device_status(2)" ) > 0)
1337   {
1338     fprintf(stderr,"port_data_lock, Port = %d\n", port);
1339   }
1340 
1341   return(stat);
1342 }
1343 
1344 
1345 
1346 
1347 
1348 //***********************************************************
1349 // channel_data()
1350 //
1351 // Takes data read in from a port and adds it to the
1352 // incoming_data_queue.  If queue is full, waits for queue to have
1353 // space before continuing.
1354 //
1355 // port #
1356 // string is the string of data
1357 // length is the length of the string.  If 0 then use strlen()
1358 // on the string itself to determine the length.
1359 //
1360 // Note that decode_ax25_header() and perhaps other routines may
1361 // increase the length of the string while processing.  We need to
1362 // send a COPY of our input string off to the decoding routines for
1363 // this reason, and the size of the buffer must be MAX_LINE_SIZE
1364 // for this reason also.
1365 //***********************************************************
channel_data(int port,unsigned char * string,volatile int length)1366 void channel_data(int port, unsigned char *string, volatile int length)
1367 {
1368   volatile int max;
1369   struct timeval tmv;
1370   // Some messiness necessary because we're using xastir_mutex's
1371   // instead of pthread_mutex_t's.
1372   pthread_mutex_t *cleanup_mutex1;
1373   pthread_mutex_t *cleanup_mutex2;
1374   // This variable defined as volatile to quash a GCC warning on some
1375   // platforms that "process_it" might be "clobbered" by a longjmp or
1376   // vfork.  There is a longjmp in forked_getaddrinfo, and somehow this
1377   // function gets involved somewhere.  If the compiler optimizes this
1378   // function just right, putting process_it into a register, that fouls
1379   // things up.  Declaring volatile silences the warning by removing
1380   // the possibility of clobbering by longjmp.
1381   volatile int process_it = 0;
1382 
1383 
1384   // Save backup copies of the incoming string and the previous
1385   // string.  Used for debugging purposes.  If we get a segfault,
1386   // we can print out the last two messages received.
1387   xastir_snprintf((char *)incoming_data_copy_previous,
1388                   sizeof(incoming_data_copy_previous),
1389                   "%s",
1390                   incoming_data_copy);
1391   xastir_snprintf((char *)incoming_data_copy,
1392                   sizeof(incoming_data_copy),
1393                   "Port%d:%s",
1394                   port,
1395                   string);
1396 
1397   max = 0;
1398 
1399   if (string == NULL)
1400   {
1401     return;
1402   }
1403 
1404   if (string[0] == '\0')
1405   {
1406     return;
1407   }
1408 
1409   if (length == 0)
1410   {
1411     // Compute length of string including terminator
1412     length = strlen((const char *)string) + 1;
1413   }
1414 
1415   // Check for excessively long packets.  These might be TCP/IP
1416   // packets or concatenated APRS packets.  In any case it's some
1417   // kind of garbage that we don't want to try to parse.
1418 
1419   // Note that for binary data (WX stations and KISS packets), the
1420   // strlen() function may not work correctly.
1421   if (length > MAX_LINE_SIZE)     // Too long!
1422   {
1423     if (debug_level & 1)
1424     {
1425       fprintf(stderr,"\nchannel_data: LONG packet:%d,  Dumping it:\n%s\n",
1426               length,
1427               string);
1428     }
1429 
1430     string[0] = '\0';   // Truncate it to zero length
1431     return;
1432   }
1433 
1434 
1435   // Install the cleanup routine for the case where this thread
1436   // gets killed while the mutex is locked.  The cleanup routine
1437   // initiates an unlock before the thread dies.  We must be in
1438   // deferred cancellation mode for the thread to have this work
1439   // properly.  We must first get the pthread_mutex_t address:
1440   cleanup_mutex1 = &output_data_lock.lock;
1441 
1442   // Then install the cleanup routine:
1443   pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex1);
1444   //    pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex1);
1445 
1446 
1447   // This protects channel_data from being run by more than one
1448   // thread at the same time.
1449   if (begin_critical_section(&output_data_lock, "interface.c:channel_data(1)" ) > 0)
1450   {
1451     fprintf(stderr,"output_data_lock, Port = %d\n", port);
1452   }
1453 
1454 
1455   if (length > 0)
1456   {
1457 
1458 
1459     // Install the cleanup routine for the case where this
1460     // thread gets killed while the mutex is locked.  The
1461     // cleanup routine initiates an unlock before the thread
1462     // dies.  We must be in deferred cancellation mode for the
1463     // thread to have this work properly.  We must first get the
1464     // pthread_mutex_t address.
1465     cleanup_mutex2 = &data_lock.lock;
1466 
1467     // Then install the cleanup routine:
1468     pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex2);
1469     //        pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex2);
1470 
1471 
1472     //        if (begin_critical_section(&data_lock, "interface.c:channel_data(2)" ) > 0)
1473     //            fprintf(stderr,"data_lock, Port = %d\n", port);
1474 
1475 
1476     // If it's any of three types of GPS ports and is a GPRMC or
1477     // GPGGA string, just stick it in one of two global
1478     // variables for holding such strings.  UpdateTime() can
1479     // come along and process/clear-out those strings at the
1480     // gps_time interval.
1481     //
1482     switch(port_data[port].device_type)
1483     {
1484 
1485       case DEVICE_SERIAL_GPS:
1486       case DEVICE_SERIAL_TNC_HSP_GPS:
1487       case DEVICE_NET_GPSD:
1488 
1489         // One of the three types of interfaces that might
1490         // send in a lot of GPS data constantly.  Save only
1491         // GPRMC and GPGGA strings into global variables.
1492         // Drop other GPS strings on the floor.
1493         //
1494         if ( (length > 7) && (isRMC((char *)string)))
1495         {
1496           xastir_snprintf(gprmc_save_string,
1497                           sizeof(gprmc_save_string),
1498                           "%s",
1499                           string);
1500           gps_port_save = port;
1501           process_it = 0;
1502         }
1503         else if ( (length > 7) && (isGGA((char *)string)))
1504         {
1505           xastir_snprintf(gpgga_save_string,
1506                           sizeof(gpgga_save_string),
1507                           "%s",
1508                           string);
1509           gps_port_save = port;
1510           process_it = 0;
1511         }
1512         else
1513         {
1514           // It's not one of the GPS strings we're looking
1515           // for.  It could be another GPS string, a
1516           // partial GPS string, or a full/partial TNC
1517           // string.  Drop the string on the floor unless
1518           // it's an HSP interface.
1519           //
1520           if (port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS)
1521           {
1522             // Decode the string normally.
1523             process_it++;
1524           }
1525         }
1526         break;
1527       // We need to make sure that the variables stating that a string is
1528       // available are reset in any case.  Look at how/where data_avail is
1529       // reset.  We may not care if we just wait for data_avail to be
1530       // cleared before writing to the string again.
1531 
1532       default:    // Not one of the above three types, decode
1533         // the string normally.
1534         process_it++;
1535         break;
1536     }
1537 
1538     // Remove the cleanup routine for the case where this thread
1539     // gets killed while the mutex is locked.  The cleanup
1540     // routine initiates an unlock before the thread dies.  We
1541     // must be in deferred cancellation mode for the thread to
1542     // have this work properly.
1543     //
1544     pthread_cleanup_pop(0);
1545 
1546 
1547     if (debug_level & 1)
1548     {
1549       fprintf(stderr,"Channel data on Port %d [%s]\n",port,(char *)string);
1550     }
1551 
1552     if (process_it)
1553     {
1554 
1555       // Wait for empty space in queue
1556       while (push_incoming_data(string, length, port) && max < 5400)
1557       {
1558         sched_yield();  // Yield to other threads
1559         tmv.tv_sec = 0;
1560         tmv.tv_usec = 2;  // 2 usec
1561         (void)select(0,NULL,NULL,NULL,&tmv);
1562         max++;
1563       }
1564     }
1565   }
1566 
1567 
1568   if (end_critical_section(&output_data_lock, "interface.c:channel_data(4)" ) > 0)
1569   {
1570     fprintf(stderr,"output_data_lock, Port = %d\n", port);
1571   }
1572 
1573   // Remove the cleanup routine for the case where this thread
1574   // gets killed while the mutex is locked.  The cleanup routine
1575   // initiates an unlock before the thread dies.  We must be in
1576   // deferred cancellation mode for the thread to have this work
1577   // properly.
1578   //
1579   pthread_cleanup_pop(0);
1580 }
1581 
1582 
1583 
1584 
1585 
1586 //********************************* START AX.25 ********************************
1587 
1588 #ifdef HAVE_LIBAX25
1589 // stolen from libax25-0.0.9 and modified to set digipeated bit based on '*'
my_ax25_aton_arglist(char * call[],struct full_sockaddr_ax25 * sax)1590 int my_ax25_aton_arglist(char *call[], struct full_sockaddr_ax25 *sax)
1591 {
1592   char *bp;
1593   char *addrp;
1594   int n = 0;
1595   int argp = 0;
1596   int len = 0;
1597   int star = 0;
1598 
1599   addrp = sax->fsa_ax25.sax25_call.ax25_call;
1600 
1601   do
1602   {
1603     /* Fetch one callsign token */
1604     if ((bp = call[argp++]) == NULL)
1605     {
1606       break;
1607     }
1608 
1609     /* Check for the optional 'via' syntax */
1610     if (n == 1 && (strcasecmp(bp, "V") == 0 || strcasecmp(bp, "VIA") == 0))
1611     {
1612       continue;
1613     }
1614 
1615     /* Process the token (Removes the star before the ax25_aton_entry call
1616        because it would call it a bad callsign.) */
1617     len = strlen(bp);
1618     if (len > 1 && bp[len-1] == '*')
1619     {
1620       star = 1;
1621       bp[len-1] = '\0';
1622     }
1623     else
1624     {
1625       star = 0;
1626     }
1627     if (ax25_aton_entry(bp, addrp) == -1)
1628     {
1629       popup_message("Bad callsign!", bp);
1630       return -1;
1631     }
1632     if (n >= 1 && star)
1633     {
1634       addrp[6] |= 0x80; // set digipeated bit if we had found a star
1635     }
1636 
1637     n++;
1638 
1639     if (n == 1)
1640     {
1641       addrp  = sax->fsa_digipeater[0].ax25_call;  /* First digipeater address */
1642     }
1643     else
1644     {
1645       addrp += sizeof(ax25_address);
1646     }
1647 
1648   }
1649   while (n < AX25_MAX_DIGIS && call[argp] != NULL);
1650 
1651   /* Tidy up */
1652   sax->fsa_ax25.sax25_ndigis = n - 1;
1653   sax->fsa_ax25.sax25_family = AF_AX25;
1654 
1655   return sizeof(struct full_sockaddr_ax25);
1656 }
1657 #endif  // HAVE_LIBAX25
1658 
1659 
1660 
1661 
1662 
1663 //***********************************************************
1664 // ui connect: change call and proto paths and reconnect net
1665 // port device to work with
1666 //***********************************************************
ui_connect(int port,char * to[])1667 int ui_connect( int port, char *to[])
1668 {
1669   int    s = -1;
1670 #ifdef HAVE_LIBAX25
1671   int    sockopt;
1672   int    addrlen = sizeof(struct full_sockaddr_ax25);
1673   struct full_sockaddr_ax25 axbind, axconnect;
1674   /* char  *arg[2]; */
1675   char  *portcall;
1676   char temp[200];
1677 
1678   if (to == NULL)
1679   {
1680     return(-1);
1681   }
1682 
1683   if (*to[0] == '\0')
1684   {
1685     return(-1);
1686   }
1687 
1688   /*
1689    * Handle incoming data
1690    *
1691    * Parse the passed values for correctness.
1692    */
1693 
1694   axconnect.fsa_ax25.sax25_family = AF_AX25;
1695   axbind.fsa_ax25.sax25_family    = AF_AX25;
1696   axbind.fsa_ax25.sax25_ndigis    = 1;
1697 
1698   if ((portcall = ax25_config_get_addr(port_data[port].device_name)) == NULL)
1699   {
1700     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00005"),
1701                     port_data[port].device_name);
1702     popup_message(langcode("POPEM00004"),temp);
1703     return -1;
1704   }
1705   if (ax25_aton_entry(portcall, axbind.fsa_digipeater[0].ax25_call) == -1)
1706   {
1707     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00006"),
1708                     port_data[port].device_name);
1709     popup_message(langcode("POPEM00004"), temp);
1710     return -1;
1711   }
1712 
1713   if (ax25_aton_entry(port_data[port].ui_call, axbind.fsa_ax25.sax25_call.ax25_call) == -1)
1714   {
1715     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00007"), port_data[port].ui_call);
1716     popup_message(langcode("POPEM00004"),temp);
1717     return -1;
1718   }
1719 
1720   if (my_ax25_aton_arglist(to, &axconnect) == -1)
1721   {
1722     popup_message(langcode("POPEM00004"),langcode("POPEM00008"));
1723     return -1;
1724   }
1725 
1726   /*
1727    * Open the socket into the kernel.
1728    */
1729 
1730   if ((s = socket(AF_AX25, SOCK_DGRAM, 0)) < 0)
1731   {
1732     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00009"), strerror(errno));
1733     popup_message(langcode("POPEM00004"),temp);
1734     return -1;
1735   }
1736 
1737   /*
1738    * Set our AX.25 callsign and AX.25 port callsign accordingly.
1739    */
1740   ENABLE_SETUID_PRIVILEGE;
1741   if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0)
1742   {
1743     DISABLE_SETUID_PRIVILEGE;
1744     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00010"), strerror(errno));
1745     popup_message(langcode("POPEM00004"),temp);
1746     return -1;
1747   }
1748   DISABLE_SETUID_PRIVILEGE;
1749 
1750   if (devices[port].relay_digipeat)
1751   {
1752     sockopt = 1;
1753   }
1754   else
1755   {
1756     sockopt = 0;
1757   }
1758 
1759   if (setsockopt(s, SOL_AX25, AX25_IAMDIGI, &sockopt, sizeof(int)))
1760   {
1761     fprintf(stderr,"AX25 IAMDIGI setsockopt FAILED");
1762     return -1;
1763   }
1764 
1765   if (debug_level & 2)
1766   {
1767     fprintf(stderr,"*** Connecting to UNPROTO port for transmission...\n");
1768   }
1769 
1770   /*
1771    * Lets try and connect to the far end.
1772    */
1773 
1774   if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0)
1775   {
1776     xastir_snprintf(temp, sizeof(temp), langcode("POPEM00011"), strerror(errno));
1777     popup_message(langcode("POPEM00004"),temp);
1778     return -1;
1779   }
1780 
1781   /*
1782    * We got there.
1783    */
1784 #endif /* HAVE_LIBAX25 */
1785   return s;
1786 }
1787 
1788 
1789 
1790 
1791 
1792 //************************************************************
1793 // data_out_ax25()
1794 //
1795 // Send string data out ax25 port
1796 //************************************************************
1797 
data_out_ax25(int port,unsigned char * string)1798 static void data_out_ax25(int port, unsigned char *string)
1799 {
1800   static char ui_mycall[10];
1801   char        *temp;
1802   char        *to[10];
1803   int         quantity;
1804 
1805   if (string == NULL)
1806   {
1807     return;
1808   }
1809 
1810   if (string[0] == '\0')
1811   {
1812     return;
1813   }
1814 
1815   if (begin_critical_section(&port_data_lock, "interface.c:data_out_ax25(1)" ) > 0)
1816   {
1817     fprintf(stderr,"port_data_lock, Port = %d\n", port);
1818   }
1819 
1820   // Check for commands (start with Control-C)
1821   if (string[0] == (unsigned char)3)   // Yes, process TNC type commands
1822   {
1823 
1824     // Look for MYCALL command
1825     if (strncmp((char *)&string[1],"MYCALL", 6) == 0)
1826     {
1827 
1828       // Found MYCALL.  Snag the callsign and put it into the
1829       // structure for the port
1830 
1831       // Look for whitespace/CR/LF (end of "MYCALL")
1832       temp = strtok((char *)&string[1]," \t\r\n");
1833       if (temp != NULL)
1834       {
1835 
1836         // Look for whitespace/CR/LF (after callsign)
1837         temp = strtok(NULL," \t\r\n");
1838         if (temp != NULL)
1839         {
1840           substr(ui_mycall, temp, 9);
1841           xastir_snprintf(port_data[port].ui_call,
1842                           sizeof(port_data[port].ui_call),
1843                           "%s",
1844                           ui_mycall);
1845           if (debug_level & 2)
1846           {
1847             fprintf(stderr,"*** MYCALL %s\n",port_data[port].ui_call);
1848           }
1849         }
1850       }
1851     }
1852 
1853     // Look for UNPROTO command
1854     else if (strncmp((char *)&string[1],"UNPROTO", 6) == 0)
1855     {
1856       quantity = 0;   // Number of callsigns found
1857 
1858       // Look for whitespace/CR/LF (end of "UNPROTO")
1859       temp = strtok((char *)&string[1]," \t\r\n");
1860       if (temp != NULL)   // Found end of "UNPROTO"
1861       {
1862 
1863         // Find first callsign (destination call)
1864         temp = strtok(NULL," \t\r\n");
1865         if (temp != NULL)
1866         {
1867           to[quantity++] = temp; // Store it
1868 
1869           // Look for "via" or "v"
1870           temp = strtok(NULL," \t\r\n");
1871 
1872           while (temp != NULL)    // Found it
1873           {
1874             // Look for the rest of the callsigns (up to
1875             // eight of them)
1876             temp = strtok(NULL," ,\t\r\n");
1877             if (temp != NULL)
1878             {
1879               if (quantity < 9)
1880               {
1881                 to[quantity++] = temp;
1882               }
1883             }
1884           }
1885           to[quantity] = NULL;
1886 
1887           if (debug_level & 2)
1888           {
1889             int i = 1;
1890 
1891             fprintf(stderr,"UNPROTO %s VIA ",*to);
1892             while (to[i] != NULL)
1893             {
1894               fprintf(stderr,"%s,",to[i++]);
1895             }
1896             fprintf(stderr,"\n");
1897           }
1898 
1899           if (port_data[port].channel2 != -1)
1900           {
1901             if (debug_level & 2)
1902             {
1903               fprintf(stderr,"Write DEVICE is UP!  Taking it down to reconfigure UI path.\n");
1904             }
1905 
1906             (void)close(port_data[port].channel2);
1907             port_data[port].channel2 = -1;
1908           }
1909 
1910           if ((port_data[port].channel2 = ui_connect(port,to)) < 0)
1911           {
1912             popup_message(langcode("POPEM00004"),langcode("POPEM00012"));
1913             port_data[port].errors++;
1914           }
1915           else      // Port re-opened and re-configured
1916           {
1917             if (debug_level & 2)
1918             {
1919               fprintf(stderr,"WRITE port re-opened after UI path change\n");
1920             }
1921           }
1922         }
1923       }
1924     }
1925   }
1926 
1927   // Else not a command, write the data directly out to the port
1928   else
1929   {
1930     if (debug_level & 2)
1931     {
1932       fprintf(stderr,"*** DATA: %s\n",(char *)string);
1933     }
1934 
1935     if (port_data[port].channel2 != -1)
1936     {
1937       if (write(port_data[port].channel2, string, strlen((char *)string)) != -1)
1938       {
1939         /* we don't actually care if this returns -1 or not
1940            but newer linux systems hate when we ignore the return
1941            value of write() */
1942       }
1943     }
1944     else if (debug_level & 2)
1945     {
1946       fprintf(stderr,"\nPort down for writing!\n\n");
1947     }
1948   }
1949 
1950   if (end_critical_section(&port_data_lock, "interface.c:data_out_ax25(2)" ) > 0)
1951   {
1952     fprintf(stderr,"port_data_lock, Port = %d\n", port);
1953   }
1954 }
1955 
1956 
1957 
1958 
1959 
1960 // fetch16bits
1961 //
1962 // Modifies: Nothing.
1963 //
fetch16bits(unsigned char * str)1964 int fetch16bits(unsigned char *str)
1965 {
1966   int i;
1967 
1968 
1969   i = *str++;
1970   i = i << 8;
1971   i = i | *str++;
1972   return(i);
1973 }
1974 
1975 
1976 
1977 
1978 
1979 // fetch32bits
1980 //
1981 // Modifies: Nothing.
1982 //
fetch32bits(unsigned char * str)1983 int fetch32bits(unsigned char *str)
1984 {
1985   int i;
1986 
1987 
1988   i = *str++;
1989   i = i << 8;
1990   i = i | *str++;
1991   i = i << 8;
1992   i = i | *str++;
1993   i = i << 8;
1994   i = i | *str;
1995   return(i);
1996 }
1997 
1998 
1999 
2000 //***********************************************************
2001 // process_ax25_packet()
2002 //
2003 // bp           raw packet data
2004 // len          length of raw packet data
2005 // buffer       buffer to write readable packet data to
2006 // buffer_size  max length of buffer
2007 //
2008 // Note that db.c:decode_ax25_header does much the same thing for
2009 // Serial KISS interface packets.  Consider combining the two
2010 // functions.  process_ax25_packet() would be the earlier and more
2011 // thought-out function.
2012 //***********************************************************
2013 
process_ax25_packet(unsigned char * bp,unsigned int len,char * buffer,int buffer_size)2014 char *process_ax25_packet(unsigned char *bp, unsigned int len, char *buffer, int buffer_size)
2015 {
2016   int i,j;
2017   unsigned int  l;
2018   unsigned int  digis;
2019   unsigned char source[10];
2020   unsigned char dest[10];
2021   unsigned char digi[10][10];
2022   unsigned char digi_h[10];
2023   unsigned int  ssid;
2024   unsigned char message[513];
2025 
2026   if ( (bp == NULL) || (buffer == NULL) )
2027   {
2028     return(NULL);
2029   }
2030 
2031   /* clear buffer */
2032   buffer[0] = '\0';
2033 
2034   if (*bp != (unsigned char)0)
2035   {
2036     return(NULL);  /* not a DATA packet */
2037   }
2038 
2039   // We have a KISS packet here, so we know that the first
2040   // character is a flag character.  Skip over it.
2041   bp++;
2042   len--;
2043 
2044   // Check the length to make sure that we don't have an empty
2045   // packet.
2046   if (!bp || !len)
2047   {
2048     return(NULL);
2049   }
2050 
2051   // Check for minimum KISS frame bytes.
2052   if (len < 15)
2053   {
2054     return(NULL);
2055   }
2056 
2057   if (bp[1] & 1) /* Compressed FlexNet Header */
2058   {
2059     return(NULL);
2060   }
2061 
2062   /* Destination of frame */
2063   j = 0;
2064   for(i = 0; i < 6; i++)
2065   {
2066     if ((bp[i] &0xfe) != (unsigned char)0x40)
2067     {
2068       dest[j++] = bp[i] >> 1;
2069     }
2070   }
2071   ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 );
2072   if (ssid != 0)
2073   {
2074     dest[j++] = '-';
2075     if ((ssid / 10) != 0)
2076     {
2077       dest[j++] = '1';
2078     }
2079     ssid = (ssid % 10);
2080     dest[j++] = (unsigned char)ssid + (unsigned char)'0';
2081   }
2082   dest[j] = '\0';
2083   bp += 7;
2084   len -= 7;
2085 
2086   /* Source of frame */
2087   j = 0;
2088   for(i = 0; i < 6; i++)
2089   {
2090     if ((bp[i] &0xfe) != (unsigned char)0x40)
2091     {
2092       source[j++] = bp[i] >> 1;
2093     }
2094   }
2095   ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 );
2096   if (ssid != 0)
2097   {
2098     source[j++] = '-';
2099     if ((ssid / 10) != 0)
2100     {
2101       source[j++] = '1';
2102     }
2103 
2104     source[j++] = (unsigned char)(ssid % 10) + (unsigned char)'0';
2105     // source[j++] = (unsigned char)ssid + (unsigned char)'0';
2106   }
2107   source[j] = '\0';
2108   bp += 7;
2109   len -= 7;
2110 
2111   // by KJ5O - test for proper extraction of source call and ssid
2112   // fprintf(stderr, "|KJ5O-test| %s-%d\n", source, ssid);
2113 
2114   /* Digipeaters */
2115   digis = 0;
2116   while ((!(bp[-1] & 1)) && (len >= 7))
2117   {
2118     /* Digi of frame */
2119     if (digis != 10)
2120     {
2121       j = 0;
2122       for (i = 0; i < 6; i++)
2123       {
2124         if ((bp[i] &0xfe) != (unsigned char)0x40)
2125         {
2126           digi[digis][j++] = bp[i] >> 1;
2127         }
2128       }
2129       digi_h[digis] = (bp[6] & 0x80);
2130       ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 );
2131       if (ssid != 0)
2132       {
2133         digi[digis][j++] = '-';
2134         if ((ssid / 10) != 0)
2135         {
2136           digi[digis][j++] = '1';
2137         }
2138         ssid = (ssid % 10);
2139         digi[digis][j++] = (unsigned char)ssid + (unsigned char)'0';
2140       }
2141       digi[digis][j] = '\0';
2142       digis++;
2143     }
2144     bp += 7;
2145     len -= 7;
2146   }
2147   if (!len)
2148   {
2149     return(NULL);
2150   }
2151 
2152   /* We are now at the primitive bit */
2153   i = (int)(*bp++);
2154   len--;
2155 
2156   /* strip the poll-bit from the primitive */
2157   i = i & (~0x10);
2158 
2159   /* return if this is not an UI frame (= 0x03) */
2160   if(i != 0x03)
2161   {
2162     return(NULL);
2163   }
2164 
2165   /* no data left */
2166   if (!len)
2167   {
2168     return(NULL);
2169   }
2170 
2171   if(*bp != (unsigned char)0xF0)     // APRS PID
2172   {
2173     // We _don't_ have an APRS packet
2174     return(NULL);
2175   }
2176 
2177   // We have what looks like a valid KISS-frame containing APRS
2178   // protocol data.
2179 
2180   bp++;
2181   len--;
2182   l = 0;
2183   while (len)
2184   {
2185     i = (int)(*bp++);
2186     if ((i != (int)'\n') && (i != (int)'\r'))
2187     {
2188       if (l < 512)
2189       {
2190         message[l++] = (unsigned char)i;
2191       }
2192     }
2193     len--;
2194   }
2195   /* add terminating '\0' to allow handling as a string */
2196   message[l] = '\0';
2197 
2198   xastir_snprintf(buffer,
2199                   buffer_size,
2200                   "%s",
2201                   source);
2202 
2203   /*
2204    * if there are no digis or the first digi has not handled the
2205    * packet then this is directly from the source, mark it with
2206    * a "*" in that case
2207    */
2208 
2209   strncat(buffer, ">", buffer_size - 1 - strlen(buffer));
2210 
2211   /* destination is at the begining of the chain, because it is  */
2212   /* needed so MIC-E packets can be decoded correctly. */
2213   /* this may be changed in the future but for now leave it here -FG */
2214   strncat(buffer, (char *)dest, buffer_size - 1 - strlen(buffer));
2215 
2216   for(i = 0; i < (int)digis; i++)
2217   {
2218     strncat(buffer, ",", buffer_size - 1 - strlen(buffer));
2219     strncat(buffer, (char *)digi[i], buffer_size - 1 - strlen(buffer));
2220     /* at the last digi always put a '*' when h_bit is set */
2221     if (i == (int)(digis - 1))
2222     {
2223       if (digi_h[i] == (unsigned char)0x80)
2224       {
2225         /* this digi must have transmitted the packet */
2226         strncat(buffer, "*", buffer_size - 1 - strlen(buffer));
2227       }
2228     }
2229     else
2230     {
2231       if (digi_h[i] == (unsigned char)0x80)
2232       {
2233         /* only put a '*' when the next digi has no h_bit */
2234         if (digi_h[i + 1] != (unsigned char)0x80)
2235         {
2236           /* this digi must have transmitted the packet */
2237           strncat(buffer, "*", buffer_size - 1 - strlen(buffer));
2238         }
2239       }
2240     }
2241   }
2242   strncat(buffer, ":", buffer_size - 1 - strlen(buffer));
2243 
2244   //Copy into only the free space in buffer.
2245   strncat( buffer, (char *)message, MAX_DEVICE_BUFFER - 1 - strlen(buffer));
2246 
2247   // And null-terminate it to make sure.
2248   buffer[MAX_DEVICE_BUFFER - 1] = '\0';
2249 
2250   return(buffer);
2251 }
2252 
2253 
2254 
2255 
2256 
2257 //*********************************************************
2258 // AX25 port INIT
2259 //
2260 // port is port# used
2261 //*********************************************************
2262 
ax25_init(int port)2263 int ax25_init(int port)
2264 {
2265 
2266   /*
2267     COMMENT:tested this Seems to work fine as ETH_P_AX25
2268     on newer linux kernels (and you see your own transmissions
2269     but it is not good for older linux kernels and FreeBSD  -FG
2270   */
2271 
2272 #ifdef HAVE_LIBAX25
2273   int proto = PF_AX25;
2274   char temp[200];
2275   char *dev = NULL;
2276 #endif  // HAVE_LIBAX25
2277 
2278   if (begin_critical_section(&port_data_lock, "interface.c:ax25_init(1)" ) > 0)
2279   {
2280     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2281   }
2282 
2283   /* clear port_channel */
2284   //    port_data[port].channel = -1;
2285 
2286   /* clear port active */
2287   port_data[port].active = DEVICE_NOT_IN_USE;
2288 
2289   /* clear port status */
2290   port_data[port].status = DEVICE_DOWN;
2291 
2292   // Show the latest status in the interface control dialog
2293   update_interface_list();
2294 
2295 #ifdef HAVE_LIBAX25
2296   if (ax25_ports_loaded == 0)
2297   {
2298     /* port file has not been loaded before now */
2299     if (ax25_config_load_ports() == 0)
2300     {
2301       fprintf(stderr, "ERROR: problem with axports file\n");
2302       popup_message(langcode("POPEM00004"),langcode("POPEM00013"));
2303 
2304       if (end_critical_section(&port_data_lock, "interface.c:ax25_init(2)" ) > 0)
2305       {
2306         fprintf(stderr,"port_data_lock, Port = %d\n", port);
2307       }
2308 
2309       return -1;
2310     }
2311     /* we can only load the port file once!!! so do not load again */
2312     ax25_ports_loaded = 1;
2313   }
2314 
2315   if (port_data[port].device_name != NULL)
2316   {
2317     if ((dev = ax25_config_get_dev(port_data[port].device_name)) == NULL)
2318     {
2319       xastir_snprintf(temp, sizeof(temp), langcode("POPEM00014"),
2320                       port_data[port].device_name);
2321       popup_message(langcode("POPEM00004"),temp);
2322 
2323       if (end_critical_section(&port_data_lock, "interface.c:ax25_init(3)" ) > 0)
2324       {
2325         fprintf(stderr,"port_data_lock, Port = %d\n", port);
2326       }
2327 
2328       return -1;
2329     }
2330   }
2331 
2332   /* COMMENT: tested this AF_INET is CORRECT -FG */
2333   // Commented out sections below.  We keep the old socket number
2334   // around now, so have to start a new socket in all cases to make it work.
2335   //    if (port_data[port].channel == -1) {
2336 
2337   ENABLE_SETUID_PRIVILEGE;
2338 #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 3
2339   port_data[port].channel = socket(PF_INET, SOCK_DGRAM, htons(proto));   // proto = AF_AX25
2340 #else   // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3
2341   port_data[port].channel = socket(PF_INET, SOCK_PACKET, htons(proto));
2342 #endif      // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3
2343   DISABLE_SETUID_PRIVILEGE;
2344 
2345   if (port_data[port].channel == -1)
2346   {
2347     perror("socket");
2348     if (end_critical_section(&port_data_lock, "interface.c:ax25_init(4)" ) > 0)
2349     {
2350       fprintf(stderr,"port_data_lock, Port = %d\n", port);
2351     }
2352 
2353     return -1;
2354   }
2355 
2356   //    }
2357   //    else {
2358   // Use socket number that is already defined
2359   //    }
2360 
2361   /* port active */
2362   port_data[port].active = DEVICE_IN_USE;
2363 
2364   /* port status */
2365   port_data[port].status = DEVICE_UP;
2366 
2367   // Show the latest status in the interface control dialog
2368   update_interface_list();
2369 
2370 #else /* HAVE_LIBAX25 */
2371   fprintf(stderr,"AX.25 support not compiled into Xastir!\n");
2372   popup_message(langcode("POPEM00004"),langcode("POPEM00021"));
2373 #endif /* HAVE_LIBAX25 */
2374   if (end_critical_section(&port_data_lock, "interface.c:ax25_init(5)" ) > 0)
2375   {
2376     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2377   }
2378 
2379   return(1);
2380 }
2381 
2382 //********************************* STOP AX.25 ********************************
2383 
2384 
2385 
2386 
2387 
2388 //*************************** START SERIAL PORT FUNCTIONS ********************************
2389 
2390 
2391 //******************************************************
2392 // command file to tnc port
2393 // port to send config data to
2394 // Filename containing the config data
2395 //******************************************************
command_file_to_tnc_port(int port,char * filename)2396 int command_file_to_tnc_port(int port, char *filename)
2397 {
2398   FILE *f;
2399   char line[MAX_LINE_SIZE+1];
2400   char command[MAX_LINE_SIZE+5];
2401   int i;
2402   char cin;
2403   int error;
2404   struct stat file_status;
2405 
2406 
2407   if (filename == NULL)
2408   {
2409     return(-1);
2410   }
2411 
2412   // Check file status
2413   if (stat(filename, &file_status) < 0)
2414   {
2415     fprintf(stderr,
2416             "Couldn't stat file: %s\n",
2417             filename);
2418     fprintf(stderr,
2419             "Skipping send to TNC\n");
2420     return(-1);
2421   }
2422 
2423   // Check that it is a regular file
2424   if (!S_ISREG(file_status.st_mode))
2425   {
2426     fprintf(stderr,
2427             "File is not a regular file: %s\n",
2428             filename);
2429     fprintf(stderr,
2430             "Skipping send to TNC\n");
2431     return(-1);
2432   }
2433 
2434   error = 0;
2435   i = 0;
2436   f = fopen(filename,"r");
2437   if (f != NULL)
2438   {
2439     int send_ctrl_C = 1;
2440 
2441     line[0] = (char)0;
2442     while (!feof(f) && error != -1)
2443     {
2444 
2445       if (fread(&cin,1,1,f) == 1)
2446       {
2447 
2448         // Check for <LF>/<CR>
2449         if (cin != (char)10 && cin != (char)13)
2450         {
2451 
2452           // If NOT <LF> or <CR>
2453           if (i < MAX_LINE_SIZE)
2454           {
2455 
2456             // Add to buffer
2457             line[i++] = cin;
2458             line[i] = (char)0;
2459           }
2460         }
2461 
2462         else    // Found a <LF> or <CR>, process line
2463         {
2464           i = 0;
2465 
2466           // Check whether comment or zero-length line
2467           if (line[0] != '#' && strlen(line) > 0)
2468           {
2469 
2470             // Line looks good.  Send it to the TNC.
2471 
2472             if (send_ctrl_C)
2473             {
2474               // Control-C desired
2475               xastir_snprintf(command,
2476                               sizeof(command),
2477                               "%c%s\r",
2478                               (char)03,   // Control-C
2479                               line);
2480             }
2481             else
2482             {
2483               // No Control-C desired
2484               xastir_snprintf(command,
2485                               sizeof(command),
2486                               "%s\r",
2487                               line);
2488             }
2489 
2490             if (debug_level & 2)
2491             {
2492               fprintf(stderr,"CMD:%s\n",command);
2493             }
2494 
2495             port_write_string(port,command);
2496             line[0] = (char)0;
2497 
2498             // Set flag to default condition
2499             send_ctrl_C = 1;
2500           }
2501           else    // Check comment to see if it is a META
2502           {
2503             // command
2504 
2505             // Should we make these ignore white-space?
2506 
2507             if (strncasecmp(line, "##META <", 8) == 0)
2508             {
2509               // Found a META command, process it
2510               if (strncasecmp(line+8, "delay", 5) == 0)
2511               {
2512                 usleep(500000); // Sleep 500ms
2513               }
2514               else if (strncasecmp(line+8, "no-ctrl-c", 9) == 0)
2515               {
2516                 // Reset the flag
2517                 send_ctrl_C = 0;
2518               }
2519               else
2520               {
2521                 fprintf(stderr,
2522                         "Unrecognized ##META command: %s\n",
2523                         line);
2524               }
2525             }
2526           }
2527         }
2528       }
2529     }
2530     (void)fclose(f);
2531   }
2532   else
2533   {
2534     if (debug_level & 2)
2535     {
2536       fprintf(stderr,"Could not open TNC command file: %s\n",filename);
2537     }
2538   }
2539 
2540   return(error);
2541 }
2542 
2543 
2544 
2545 
2546 
2547 //***********************************************************
2548 // port_dtr INIT
2549 // port is port# used
2550 // dtr 1 is down, 0 is normal(up)
2551 //***********************************************************
port_dtr(int port,int dtr)2552 void port_dtr(int port, int dtr)
2553 {
2554 
2555   // It looks like we have two methods of getting this to compile on
2556   // CYGWIN, getting rid of the entire procedure contents, and getting
2557   // rid of the TIO* code.  One method or the other should work to get
2558   // it compiled.  We shouldn't need both.
2559   int sg;
2560 
2561   /* check for 1 or 0 */
2562   dtr = (dtr & 0x1);
2563 
2564   if (begin_critical_section(&port_data_lock, "interface.c:port_dtr(1)" ) > 0)
2565   {
2566     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2567   }
2568 
2569   if (port_data[port].active == DEVICE_IN_USE
2570       && port_data[port].status == DEVICE_UP
2571       && port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS)
2572   {
2573 
2574     port_data[port].dtr = dtr;
2575     if (debug_level & 2)
2576     {
2577       fprintf(stderr,"DTR %d\n",port_data[port].dtr);
2578     }
2579 
2580 #ifdef TIOCMGET
2581     ENABLE_SETUID_PRIVILEGE;
2582     (void)ioctl(port_data[port].channel, TIOCMGET, &sg);
2583     DISABLE_SETUID_PRIVILEGE;
2584 #endif  // TIOCMGET
2585 
2586     sg &= 0xff;
2587 
2588 #ifdef TIOCM_DTR
2589 
2590     // ugly HPUX hack - n8ysz 20041206
2591 
2592 #ifndef MDTR
2593 #define MDTR 99999
2594 #if (TIOCM_DTR == 99999)
2595 #include <sys/modem.h>
2596 #endif
2597 #endif
2598 
2599     // end ugly hack
2600 
2601     sg = TIOCM_DTR;
2602 #endif  // TIOCM_DIR
2603 
2604     if (dtr)
2605     {
2606       dtr &= ~sg;
2607 
2608 #ifdef TIOCMBIC
2609       ENABLE_SETUID_PRIVILEGE;
2610       (void)ioctl(port_data[port].channel, TIOCMBIC, &sg);
2611       DISABLE_SETUID_PRIVILEGE;
2612 #endif  // TIOCMBIC
2613 
2614       if (debug_level & 2)
2615       {
2616         fprintf(stderr,"Down\n");
2617       }
2618 
2619       // statusline(langcode("BBARSTA026"),1);
2620 
2621     }
2622     else
2623     {
2624       dtr |= sg;
2625 
2626 #ifdef TIOCMBIS
2627       ENABLE_SETUID_PRIVILEGE;
2628       (void)ioctl(port_data[port].channel, TIOCMBIS, &sg);
2629       DISABLE_SETUID_PRIVILEGE;
2630 #endif  // TIOCMBIS
2631 
2632       if (debug_level & 2)
2633       {
2634         fprintf(stderr,"UP\n");
2635       }
2636 
2637       // statusline(langcode("BBARSTA027"),1);
2638     }
2639   }
2640 
2641   if (end_critical_section(&port_data_lock, "interface.c:port_dtr(2)" ) > 0)
2642   {
2643     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2644   }
2645 }
2646 
2647 
2648 
2649 
2650 
2651 //***********************************************************
2652 // port_dtr INIT
2653 // port is port# used
2654 // dtr 1 is down, 0 is normal(up)
2655 //***********************************************************
dtr_all_set(int dtr)2656 void dtr_all_set(int dtr)
2657 {
2658   int i;
2659 
2660   for (i = 0; i < MAX_IFACE_DEVICES; i++)
2661   {
2662     if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS
2663         && port_data[i].status == DEVICE_UP)
2664     {
2665       port_dtr(i,dtr);
2666     }
2667   }
2668 }
2669 
2670 
2671 
2672 
2673 
2674 //***********************************************************
2675 // Serial port close.  Remove the lockfile as well.
2676 // port is port# used
2677 //***********************************************************
serial_detach(int port)2678 int serial_detach(int port)
2679 {
2680   char fn[600];
2681   int ok;
2682   ok = -1;
2683 
2684   if (begin_critical_section(&port_data_lock, "interface.c:serial_detach(1)" ) > 0)
2685   {
2686     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2687   }
2688 
2689   if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP)
2690   {
2691 
2692     // Close port first
2693     (void)tcsetattr(port_data[port].channel, TCSANOW, &port_data[port].t_old);
2694     if (close(port_data[port].channel) == 0)
2695     {
2696       port_data[port].status = DEVICE_DOWN;
2697       usleep(200);
2698       port_data[port].active = DEVICE_NOT_IN_USE;
2699       ok = 1;
2700 
2701       // Show the latest status in the interface control dialog
2702       update_interface_list();
2703     }
2704     else
2705     {
2706       if (debug_level & 2)
2707       {
2708         fprintf(stderr,"Could not close port %s\n",port_data[port].device_name);
2709       }
2710 
2711       port_data[port].status = DEVICE_DOWN;
2712       usleep(200);
2713       port_data[port].active = DEVICE_NOT_IN_USE;
2714 
2715       // Show the latest status in the interface control dialog
2716       update_interface_list();
2717     }
2718 
2719     // Delete lockfile
2720     xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name));
2721     if (debug_level & 2)
2722     {
2723       fprintf(stderr,"Delete lock file %s\n",fn);
2724     }
2725 
2726     ENABLE_SETUID_PRIVILEGE;
2727     (void)unlink(fn);
2728     DISABLE_SETUID_PRIVILEGE;
2729   }
2730   else
2731   {
2732 
2733     // If we didn't have the port in use, for instance we
2734     // weren't able to open it, we should check whether a
2735     // lockfile exists for the port and see if another running
2736     // process owns the lockfile (the PID of the owner is inside
2737     // the lockfile).  If not, remove the lockfile 'cuz it may
2738     // have been ours from this or a previous run.  Note that we
2739     // can now run multiple Xastir sessions from a single user,
2740     // and the lockfiles must be kept straight between them.  If
2741     // a lockfile doesn't contain a PID from a running process,
2742     // it's fair game to delete the lockfile and/or take over
2743     // the port with a new lockfile.
2744     //
2745     //   if (lockfile exists) {
2746     //       PID = read contents of lockfile
2747     //       if (PID is running) {
2748     //           Do nothing, leave the file alone
2749     //       }
2750     //       else {
2751     //           Delete the lockfile
2752     //       }
2753     //   }
2754   }
2755 
2756   if (end_critical_section(&port_data_lock, "interface.c:serial_detach(2)" ) > 0)
2757   {
2758     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2759   }
2760 
2761   return(ok);
2762 }
2763 
2764 
2765 
2766 
2767 
2768 //***********************************************************
2769 // Serial port INIT
2770 // port is port# used
2771 //***********************************************************
serial_init(int port)2772 int serial_init (int port)
2773 {
2774   FILE *lock;
2775   int speed;
2776   pid_t mypid = 0;
2777   pid_t lockfile_pid = 0;
2778   int lockfile_intpid;
2779   char fn[600];
2780   uid_t user_id;
2781   struct passwd *user_info;
2782   char temp[100];
2783   char temp1[100];
2784   pid_t status;
2785   int ii;
2786   int myerrno;
2787 
2788   status = -9999;
2789 
2790   if (begin_critical_section(&port_data_lock, "interface.c:serial_init(1)" ) > 0)
2791   {
2792     fprintf(stderr,"port_data_lock, Port = %d\n", port);
2793   }
2794 
2795   // clear port_channel
2796   port_data[port].channel = -1;
2797 
2798   // clear port active
2799   port_data[port].active = DEVICE_NOT_IN_USE;
2800 
2801   // clear port status
2802   port_data[port].status = DEVICE_DOWN;
2803 
2804   // Show the latest status in the interface control dialog
2805   update_interface_list();
2806 
2807 
2808   // Check whether we have a port with the same device already
2809   // open.  Check all ports except this one and check for
2810   // DEVICE_IN_USE.  If found, check whether the device_name
2811   // matches.  If a match, skip initializing this port.
2812   //
2813   for (ii = 0; ii < MAX_IFACE_DEVICES; ii++)
2814   {
2815     if (ii != port)
2816     {
2817       if (port_data[ii].active == DEVICE_IN_USE)
2818       {
2819         if (strcmp(port_data[ii].device_name, port_data[port].device_name) == 0)
2820         {
2821           // Found a port with the same device_name which
2822           // is already active.  Skip bringing up another
2823           // interface on the same port.
2824           return(-1);
2825         }
2826       }
2827     }
2828   }
2829 
2830 
2831   // check for lockfile
2832   xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s",
2833                   get_device_name_only(port_data[port].device_name));
2834 
2835   if (filethere(fn) == 1)
2836   {
2837 
2838     // Also look for pid of other process and see if it is a valid lock
2839     fprintf(stderr,"Found an existing lockfile %s for this port!\n",fn);
2840 
2841     lock = fopen(fn,"r");
2842     if (lock != NULL)   // We could open it so it must have
2843     {
2844       // been created by this userid
2845       if (fscanf(lock,"%d %99s %99s",&lockfile_intpid,temp,temp1) == 3)
2846       {
2847         lockfile_pid = (pid_t)lockfile_intpid;
2848 
2849 #ifdef HAVE_GETPGRP
2850 #ifdef GETPGRP_VOID
2851         // Won't this one get our process group instead of
2852         // the process group for the lockfile?  Not of that
2853         // much use to us here.
2854         status = getpgrp();
2855 #else // GETPGRP_VOID
2856         status = getpgrp(lockfile_pid);
2857 #endif // GETPGRP_VOID
2858 #else   // HAVE_GETPGRP
2859         status = getpgid(lockfile_pid);
2860 #endif // HAVE_GETPGRP
2861 
2862       }
2863       else
2864       {
2865         // fscanf parsed the wrong number of items.
2866         // lockfile is different, perhaps created by some
2867         // other program.
2868       }
2869 
2870       (void)fclose(lock);
2871 
2872       // See whether the existing lockfile is stale.  Remove
2873       // the file if it belongs to our process group or if the
2874       // PID in the file is no longer running.
2875       //
2876       // The only time we _shouldn't_ delete the file and
2877       // claim the port for our own is when the process that
2878       // created the lockfile is still running.
2879 
2880       // Get my process id
2881       mypid = getpid();
2882 
2883       // If status = -1, the process that created the lockfile
2884       // is no longer running and of course will not match
2885       // "lockfile_pid", so we can delete it.
2886       //
2887       // If "lockfile_pid == mypid", then this currently
2888       // running instance of Xastir was the one that created
2889       // the lockfile and it is again ok to delete it.
2890       //
2891       if (status != lockfile_pid || lockfile_pid == mypid)
2892       {
2893         fprintf(stderr,"Lock is stale!  Removing it.\n");
2894         ENABLE_SETUID_PRIVILEGE;
2895         (void)unlink(fn);
2896         DISABLE_SETUID_PRIVILEGE;
2897       }
2898       else
2899       {
2900         fprintf(stderr,"Cannot open port:  Another program has the lock!\n");
2901 
2902         if (end_critical_section(&port_data_lock, "interface.c:serial_init(2)" ) > 0)
2903         {
2904           fprintf(stderr,"port_data_lock, Port = %d\n", port);
2905         }
2906 
2907         return (-1);
2908       }
2909     }
2910     else      // Couldn't open it, so the lock must have been
2911     {
2912       // created by another userid
2913       fprintf(stderr,"Cannot open port:  Lockfile cannot be opened!\n");
2914 
2915       if (end_critical_section(&port_data_lock, "interface.c:serial_init(3)" ) > 0)
2916       {
2917         fprintf(stderr,"port_data_lock, Port = %d\n", port);
2918       }
2919 
2920       return (-1);
2921     }
2922   }
2923 
2924   // Try to open the serial port now
2925   ENABLE_SETUID_PRIVILEGE;
2926   port_data[port].channel = open(port_data[port].device_name, O_RDWR|O_NOCTTY);
2927   myerrno = errno;
2928   DISABLE_SETUID_PRIVILEGE;
2929   if (port_data[port].channel == -1)
2930   {
2931 
2932     if (end_critical_section(&port_data_lock, "interface.c:serial_init(4)" ) > 0)
2933     {
2934       fprintf(stderr,"port_data_lock, Port = %d\n", port);
2935     }
2936 
2937     if (debug_level & 2)
2938     {
2939       fprintf(stderr,"Could not open channel on port %d!\n",port);
2940     }
2941 
2942     switch (myerrno)
2943     {
2944 
2945       case EACCES:
2946         fprintf(stderr,"\tEACCESS ERROR\n");
2947         break;
2948 
2949       case EEXIST:
2950         fprintf(stderr,"\tEEXIST ERROR\n");
2951         break;
2952 
2953       case EFAULT:
2954         fprintf(stderr,"\tEFAULT ERROR\n");
2955         break;
2956 
2957       case EISDIR:
2958         fprintf(stderr,"\tEISDIR ERROR\n");
2959         break;
2960 
2961       case ELOOP:
2962         fprintf(stderr,"\tELOOP ERROR\n");
2963         break;
2964 
2965       case EMFILE:
2966         fprintf(stderr,"\tEMFILE ERROR\n");
2967         break;
2968 
2969       case ENAMETOOLONG:
2970         fprintf(stderr,"\tENAMETOOLONG ERROR\n");
2971         break;
2972 
2973       case ENFILE:
2974         fprintf(stderr,"\tEMFILE ERROR\n");
2975         break;
2976 
2977       case ENODEV:
2978         fprintf(stderr,"\tENODEV ERROR\n");
2979         break;
2980 
2981       case ENOENT:
2982         fprintf(stderr,"\tENOENT ERROR\n");
2983         break;
2984 
2985       case ENOMEM:
2986         fprintf(stderr,"\tENOMEM ERROR\n");
2987         break;
2988 
2989       case ENOSPC:
2990         fprintf(stderr,"\tENOSPC ERROR\n");
2991         break;
2992 
2993       case ENOTDIR:
2994         fprintf(stderr,"\tENOTDIR ERROR\n");
2995         break;
2996 
2997       case ENXIO:
2998         fprintf(stderr,"\tENXIO ERROR\n");
2999         break;
3000 
3001       case EOVERFLOW:
3002         fprintf(stderr,"\tEOVERFLOW ERROR\n");
3003         break;
3004 
3005       case EPERM:
3006         fprintf(stderr,"\tEPERM ERROR\n");
3007         break;
3008 
3009       case EROFS:
3010         fprintf(stderr,"\tEROFS ERROR\n");
3011         break;
3012 
3013       case ETXTBSY:
3014         fprintf(stderr,"\tETXTBSY ERROR\n");
3015         break;
3016 
3017       default:
3018         fprintf(stderr,"\tOTHER ERROR\n");
3019         break;
3020     }
3021 
3022     return (-1);
3023   }
3024 
3025   // Attempt to create the lockfile
3026   xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name));
3027   if (debug_level & 2)
3028   {
3029     fprintf(stderr,"Create lock file %s\n",fn);
3030   }
3031 
3032   ENABLE_SETUID_PRIVILEGE;
3033   lock = fopen(fn,"w");
3034   DISABLE_SETUID_PRIVILEGE;
3035   if (lock != NULL)
3036   {
3037     // get my process id for lockfile
3038     mypid = getpid();
3039 
3040     // get user info
3041     user_id = getuid();
3042     user_info = getpwuid(user_id);
3043     xastir_snprintf(temp,
3044                     sizeof(temp),
3045                     "%s",
3046                     user_info->pw_name);
3047 
3048     fprintf(lock,"%9d %s %s",(int)mypid,"xastir",temp);
3049     (void)fclose(lock);
3050     // We've successfully created our own lockfile
3051   }
3052   else
3053   {
3054     // lock failed
3055     if (debug_level & 2)
3056     {
3057       fprintf(stderr,"Warning:  Failed opening LCK file!  Continuing on...\n");
3058     }
3059 
3060     /* if we can't create lockfile don't fail!
3061 
3062        if (end_critical_section(&port_data_lock, "interface.c:serial_init(5)" ) > 0)
3063        fprintf(stderr,"port_data_lock, Port = %d\n", port);
3064 
3065        return (-1);*/
3066   }
3067 
3068   // get port attributes for new and old
3069   if (tcgetattr(port_data[port].channel, &port_data[port].t) != 0)
3070   {
3071 
3072     if (end_critical_section(&port_data_lock, "interface.c:serial_init(6)" ) > 0)
3073     {
3074       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3075     }
3076 
3077     if (debug_level & 2)
3078     {
3079       fprintf(stderr,"Could not get t port attributes for port %d!\n",port);
3080     }
3081 
3082     // Close the port and remove the lock.
3083     serial_detach(port);
3084 
3085     return (-1);
3086   }
3087 
3088   if (tcgetattr(port_data[port].channel, &port_data[port].t_old) != 0)
3089   {
3090 
3091     if (end_critical_section(&port_data_lock, "interface.c:serial_init(7)" ) > 0)
3092     {
3093       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3094     }
3095 
3096     if (debug_level & 2)
3097     {
3098       fprintf(stderr,"Could not get t_old port attributes for port %d!\n",port);
3099     }
3100 
3101     // Close the port and remove the lock.
3102     serial_detach(port);
3103 
3104     return (-1);
3105   }
3106 
3107   // set time outs
3108   port_data[port].t.c_cc[VMIN] = (cc_t)1;
3109   port_data[port].t.c_cc[VTIME] = (cc_t)2;
3110 
3111   // set port flags
3112   port_data[port].t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
3113   port_data[port].t.c_iflag = (tcflag_t)(IGNBRK | IGNPAR);
3114 
3115   port_data[port].t.c_oflag = (0);
3116   port_data[port].t.c_lflag = (0);
3117 
3118 #ifdef    CBAUD
3119   speed = (int)(port_data[port].t.c_cflag & CBAUD);
3120 #else   // CBAUD
3121   speed = 0;
3122 #endif  // CBAUD
3123   port_data[port].t.c_cflag = (tcflag_t)(HUPCL|CLOCAL|CREAD);
3124   port_data[port].t.c_cflag &= ~PARENB;
3125   switch (port_data[port].style)
3126   {
3127     case(0):
3128       // No parity (8N1)
3129       port_data[port].t.c_cflag &= ~CSTOPB;
3130       port_data[port].t.c_cflag &= ~CSIZE;
3131       port_data[port].t.c_cflag |= CS8;
3132       break;
3133 
3134     case(1):
3135       // Even parity (7E1)
3136       port_data[port].t.c_cflag &= ~PARODD;
3137       port_data[port].t.c_cflag &= ~CSTOPB;
3138       port_data[port].t.c_cflag &= ~CSIZE;
3139       port_data[port].t.c_cflag |= CS7;
3140       break;
3141 
3142     case(2):
3143       // Odd parity (7O1):
3144       port_data[port].t.c_cflag |= PARODD;
3145       port_data[port].t.c_cflag &= ~CSTOPB;
3146       port_data[port].t.c_cflag &= ~CSIZE;
3147       port_data[port].t.c_cflag |= CS7;
3148       break;
3149 
3150     default:
3151       break;
3152   }
3153 
3154   port_data[port].t.c_cflag |= speed;
3155   // set input and out put speed
3156   if (cfsetispeed(&port_data[port].t, port_data[port].sp) == -1)
3157   {
3158 
3159     if (end_critical_section(&port_data_lock, "interface.c:serial_init(8)" ) > 0)
3160     {
3161       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3162     }
3163 
3164     if (debug_level & 2)
3165     {
3166       fprintf(stderr,"Could not set port input speed for port %d!\n",port);
3167     }
3168 
3169     // Close the port and remove the lock.
3170     serial_detach(port);
3171 
3172     return (-1);
3173   }
3174 
3175   if (cfsetospeed(&port_data[port].t, port_data[port].sp) == -1)
3176   {
3177 
3178     if (end_critical_section(&port_data_lock, "interface.c:serial_init(9)" ) > 0)
3179     {
3180       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3181     }
3182 
3183     if (debug_level & 2)
3184     {
3185       fprintf(stderr,"Could not set port output speed for port %d!\n",port);
3186     }
3187 
3188     // Close the port and remove the lock.
3189     serial_detach(port);
3190 
3191     return (-1);
3192   }
3193 
3194   if (tcflush(port_data[port].channel, TCIFLUSH) == -1)
3195   {
3196 
3197     if (end_critical_section(&port_data_lock, "interface.c:serial_init(10)" ) > 0)
3198     {
3199       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3200     }
3201 
3202     if (debug_level & 2)
3203     {
3204       fprintf(stderr,"Could not flush data for port %d!\n",port);
3205     }
3206 
3207     // Close the port and remove the lock.
3208     serial_detach(port);
3209 
3210     return (-1);
3211   }
3212 
3213   if (tcsetattr(port_data[port].channel,TCSANOW, &port_data[port].t) == -1)
3214   {
3215 
3216     if (end_critical_section(&port_data_lock, "interface.c:serial_init(11)" ) > 0)
3217     {
3218       fprintf(stderr,"port_data_lock, Port = %d\n", port);
3219     }
3220 
3221     if (debug_level & 2)
3222     {
3223       fprintf(stderr,"Could not set port attributes for port %d!\n",port);
3224     }
3225 
3226     // Close the port and remove the lock.
3227     serial_detach(port);
3228 
3229     return (-1);
3230   }
3231 
3232   // clear port active
3233   port_data[port].active = DEVICE_IN_USE;
3234 
3235   // clear port status
3236   port_data[port].status = DEVICE_UP;
3237 
3238   // Show the latest status in the interface control dialog
3239   update_interface_list();
3240 
3241   if (end_critical_section(&port_data_lock, "interface.c:serial_init(12)" ) > 0)
3242   {
3243     fprintf(stderr,"port_data_lock, Port = %d\n", port);
3244   }
3245 
3246   // return good condition
3247   return (1);
3248 }
3249 
3250 //*************************** STOP SERIAL PORT FUNCTIONS ********************************
3251 
3252 
3253 
3254 
3255 
3256 //***************************** START NETWORK FUNCTIONS *********************************
3257 
3258 //**************************************************************
3259 // net_connect_thread()
3260 // Temporary thread used to start up a socket.
3261 //**************************************************************
net_connect_thread(void * arg)3262 static void* net_connect_thread(void *arg)
3263 {
3264   int port;
3265   volatile int ok = -1;
3266   int result=-1;
3267   int flag;
3268   //int stat;
3269   struct addrinfo *res;
3270 
3271   // Some messiness necessary because we're using
3272   // xastir_mutex's instead of pthread_mutex_t's.
3273   pthread_mutex_t *cleanup_mutex;
3274 
3275 
3276   if (debug_level & 2)
3277   {
3278     fprintf(stderr,"net_connect_thread start\n");
3279   }
3280 
3281   port = *((int *) arg);
3282   // This call means we don't care about the return code and won't
3283   // use pthread_join() later.  Makes threading more efficient.
3284   (void)pthread_detach(pthread_self());
3285 
3286   for (res = port_data[port].addr_list; res; res = res->ai_next)
3287   {
3288 
3289     pthread_testcancel();   // Check for thread termination request
3290     port_data[port].channel = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
3291     pthread_testcancel();   // Check for thread termination request
3292 
3293     if (port_data[port].channel == -1)
3294     {
3295       fprintf(stderr, "Socket creation for type (%d, %d, %d) failed: %s\n",
3296               res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) );
3297       fprintf(stderr, "This may be OK if we have more to try.\n");
3298       continue;
3299     }
3300 
3301     if (debug_level & 2)
3302     {
3303       fprintf(stderr,"We have a socket to use\n");
3304     }
3305     flag = 1;
3306 
3307     // Turn on the socket keepalive option
3308     (void)setsockopt(port_data[port].channel,  SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int));
3309 
3310     // Disable the Nagle algorithm (speeds things up)
3311     (void)setsockopt(port_data[port].channel, IPPROTO_TCP,  TCP_NODELAY, (char *) &flag, sizeof(int));
3312 
3313     if (debug_level & 2)
3314     {
3315       fprintf(stderr,"after setsockopt\n");
3316     }
3317     pthread_testcancel();  // Check for thread termination request
3318     if (debug_level & 2)
3319     {
3320       fprintf(stderr,"calling connect(), port: %d\n", port_data[port].socket_port);
3321     }
3322     result = connect(port_data[port].channel, res->ai_addr, res->ai_addrlen);
3323     if (debug_level & 2)
3324     {
3325       fprintf(stderr,"connect result was: %d\n", result);
3326     }
3327     if(result == 0 )
3328     {
3329       break;
3330     }
3331     if(result == -1)
3332     {
3333       fprintf(stderr, "Socket connection for interface %d type (%d, %d, %d) failed: %s\n",
3334               port, res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) );
3335       if(res->ai_next)
3336       {
3337         fprintf(stderr, "This is OK since we have more to try.\n");
3338       }
3339       close(port_data[port].channel);
3340       port_data[port].channel = -1;
3341       continue;
3342     }
3343   }
3344   ok = 0;
3345   pthread_testcancel();  // Check for thread termination request
3346   if (result != -1)
3347   {
3348     /* connection up */
3349     if (debug_level & 2)
3350     {
3351       fprintf(stderr,"net_connect_thread():Net up, port %d\n",port);
3352     }
3353 
3354     port_data[port].status = DEVICE_UP;
3355     ok = 1;
3356 
3357     // Show the latest status in the interface control dialog
3358     update_interface_list();
3359   }
3360   else      /* net connection failed */
3361   {
3362     ok = 0;
3363     if (debug_level & 2)
3364     {
3365       fprintf(stderr,"net_connect_thread():net connection failed, port %d, DEVICE_ERROR ***\n",port);
3366     }
3367     port_data[port].status = DEVICE_ERROR;
3368 
3369     // Show the latest status in the interface control dialog
3370     update_interface_list();
3371 
3372     usleep(100000); // 100ms
3373     // Note:  Old comments note that it is essential not to shut down
3374     // the socket here, because the connection didn't actually happen,
3375     // and multithreading could lead to the socket number having
3376     // already been reused elsewhere.
3377   }
3378 
3379   // Install the cleanup routine for the case where this thread
3380   // gets killed while the mutex is locked.  The cleanup routine
3381   // initiates an unlock before the thread dies.  We must be in
3382   // deferred cancellation mode for the thread to have this work
3383   // properly.  We must first get the pthread_mutex_t address:
3384   cleanup_mutex = &connect_lock.lock;
3385 
3386   // Then install the cleanup routine:
3387   pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex);
3388 
3389   if (begin_critical_section(&connect_lock, "interface.c:net_connect_thread(2)" ) > 0)
3390   {
3391     fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port);
3392   }
3393 
3394   port_data[port].connect_status = ok;
3395   port_data[port].thread_status = 0;
3396 
3397   if (end_critical_section(&connect_lock, "interface.c:net_connect_thread(3)" ) > 0)
3398   {
3399     fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port);
3400   }
3401 
3402   // Remove the cleanup routine for the case where this thread
3403   // gets killed while the mutex is locked.  The cleanup routine
3404   // initiates an unlock before the thread dies.  We must be in
3405   // deferred cancellation mode for the thread to have this work
3406   // properly.
3407   //
3408   pthread_cleanup_pop(0);
3409 
3410   if (debug_level & 2)
3411   {
3412     fprintf(stderr,"net_connect_thread terminating itself\n");
3413   }
3414 
3415   return(NULL);   // This should kill the thread
3416 }
3417 
3418 
3419 
3420 
3421 
3422 //**************************************************************
3423 // net_init()
3424 //
3425 // This brings up a network connection
3426 //
3427 // returns -1 on hard error, 0 on time out, 1 if ok
3428 //**************************************************************
net_init(int port)3429 int net_init(int port)
3430 {
3431   int ok;
3432   char st[200];
3433   pthread_t connect_thread;
3434   int stat;
3435   int wait_on_connect;
3436   time_t wait_time;
3437   int gai_rc;     // Return code from get address info
3438   char port_num[16];
3439   struct addrinfo hints;
3440 
3441   if (begin_critical_section(&port_data_lock, "interface.c:net_init(1)" ) > 0)
3442   {
3443     fprintf(stderr,"port_data_lock, Port = %d\n", port);
3444   }
3445 
3446   /* set port active */
3447   port_data[port].active = DEVICE_IN_USE;
3448 
3449   /* clear port status */
3450   port_data[port].status = DEVICE_DOWN;
3451 
3452   // Show the latest status in the interface control dialog
3453   update_interface_list();
3454 
3455   ok = -1;
3456 
3457 
3458   hints.ai_family = AF_UNSPEC;
3459   hints.ai_socktype = SOCK_STREAM;
3460   hints.ai_protocol = 0;
3461   hints.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG;
3462   xastir_snprintf(port_num, sizeof(port_num), "%d", port_data[port].socket_port);
3463 
3464   xastir_snprintf(st, sizeof(st), langcode("BBARSTA019"), port_data[port].device_host_name);
3465   statusline(st,1);   // Looking up host
3466 
3467   if(port_data[port].addr_list)
3468   {
3469     forked_freeaddrinfo(port_data[port].addr_list);
3470     port_data[port].addr_list = NULL;
3471   }
3472   gai_rc = forked_getaddrinfo(port_data[port].device_host_name, port_num, &hints, &port_data[port].addr_list, 13);
3473 
3474   if(gai_rc == 0)
3475   {
3476     /* ok try to connect */
3477 
3478     if (begin_critical_section(&connect_lock, "interface.c:net_init(2)" ) > 0)
3479     {
3480       fprintf(stderr,"connect_lock, Port = %d\n", port);
3481     }
3482 
3483     port_data[port].thread_status = 1;
3484     port_data[port].connect_status = -1;
3485 
3486     // If channel is != -1, we have a socket remaining from a previous
3487     // connect attempt.  Shutdown and close that socket, then create
3488     // a new one.
3489     if (port_data[port].channel != -1)      // We have a socket already
3490     {
3491 
3492       // Shut down and close the socket
3493       pthread_testcancel();   // Check for thread termination request
3494       stat = shutdown(port_data[port].channel,2);
3495       pthread_testcancel();   // Check for thread termination request
3496       if (debug_level & 2)
3497       {
3498         fprintf(stderr,"net_connect_thread():Net Shutdown 1 Returned %d, port %d\n",stat,port);
3499       }
3500       usleep(100000);         // 100ms
3501       pthread_testcancel();   // Check for thread termination request
3502       stat = close(port_data[port].channel);
3503       pthread_testcancel();   // Check for thread termination request
3504       if (debug_level & 2)
3505       {
3506         fprintf(stderr,"net_connect_thread():Net Close 1 Returned %d, port %d\n",stat,port);
3507       }
3508       usleep(100000);         // 100ms
3509       port_data[port].channel = -1;
3510     }
3511 
3512     if (end_critical_section(&connect_lock, "interface.c:net_init(3)" ) > 0)
3513     {
3514       fprintf(stderr,"connect_lock, Port = %d\n", port);
3515     }
3516 
3517     if (debug_level & 2)
3518     {
3519       fprintf(stderr,"Creating new thread\n");
3520     }
3521     if (pthread_create(&connect_thread, NULL, net_connect_thread, &port))
3522     {
3523       /* error starting thread*/
3524       ok = -1;
3525       fprintf(stderr,"Error creating net_connect thread, port %d\n",port);
3526     }
3527 
3528     busy_cursor(appshell);
3529     wait_time = sec_now() + NETWORK_WAITTIME;  // Set ending time for wait
3530     wait_on_connect = 1;
3531     while (wait_on_connect && (sec_now() < wait_time))
3532     {
3533 
3534       if (begin_critical_section(&connect_lock, "interface.c:net_init(4)" ) > 0)
3535       {
3536         fprintf(stderr,"connect_lock, Port = %d\n", port);
3537       }
3538 
3539       wait_on_connect = port_data[port].thread_status;
3540 
3541       if (end_critical_section(&connect_lock, "interface.c:net_init(5)" ) > 0)
3542       {
3543         fprintf(stderr,"connect_lock, Port = %d\n", port);
3544       }
3545 
3546       xastir_snprintf(st, sizeof(st), langcode("BBARSTA025"), wait_time - sec_now() );
3547       statusline(st,1);           // Host found, connecting n
3548       if (debug_level & 2)
3549       {
3550         fprintf(stderr,"%d\n", (int)(wait_time - sec_now()) );
3551       }
3552 
3553       usleep(250000);      // 250mS
3554     }
3555 
3556     ok = port_data[port].connect_status;
3557 
3558     /* thread did not return! kill it */
3559     if ( (sec_now() >= wait_time)      // Timed out
3560          || (ok != 1) )              // or connection failure of another type
3561     {
3562       if (debug_level & 2)
3563       {
3564         fprintf(stderr,"Thread exceeded it's time limit or failed to connect! Port %d\n",port);
3565       }
3566 
3567       if (begin_critical_section(&connect_lock, "interface.c:net_init(6)" ) > 0)
3568       {
3569         fprintf(stderr,"connect_lock, Port = %d\n", port);
3570       }
3571 
3572       if (debug_level & 2)
3573       {
3574         fprintf(stderr,"Killing thread\n");
3575       }
3576       if (pthread_cancel(connect_thread))
3577       {
3578         // The only error code we can get here is ESRCH, which means
3579         // that the thread number wasn't found.  The thread is already
3580         // dead, so let's not print out an error code.
3581       }
3582 
3583       if (sec_now() >= wait_time)    // Timed out
3584       {
3585         port_data[port].connect_status = -2;
3586         if (debug_level & 2)
3587         {
3588           fprintf(stderr,"It was a timeout.\n");
3589         }
3590       }
3591 
3592       if (end_critical_section(&connect_lock, "interface.c:net_init(7)" ) > 0)
3593       {
3594         fprintf(stderr,"connect_lock, Port = %d\n", port);
3595       }
3596 
3597       port_data[port].status = DEVICE_ERROR;
3598       if (debug_level & 2)
3599       {
3600         fprintf(stderr,"Thread did not return, port %d, DEVICE_ERROR ***\n",port);
3601       }
3602 
3603       // Show the latest status in the interface control dialog
3604       update_interface_list();
3605     }
3606     if (begin_critical_section(&connect_lock, "interface.c:net_init(8)" ) > 0)
3607     {
3608       fprintf(stderr,"connect_lock, Port = %d\n", port);
3609     }
3610 
3611     ok = port_data[port].connect_status;
3612 
3613     if (end_critical_section(&connect_lock, "interface.c:net_init(9)" ) > 0)
3614     {
3615       fprintf(stderr,"connect_lock, Port = %d\n", port);
3616     }
3617 
3618     if (debug_level & 2)
3619     {
3620       fprintf(stderr,"Net ok: %d, port %d\n", ok, port);
3621     }
3622 
3623     switch (ok)
3624     {
3625       case 1: /* connection up */
3626         xastir_snprintf(st, sizeof(st), langcode("BBARSTA020"), port_data[port].device_host_name);
3627         statusline(st,1);               // Connected to ...
3628         break;
3629 
3630       case 0:
3631         xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA021"));
3632         statusline(st,1);               // Net Connection Failed!
3633         ok = -1;
3634         break;
3635 
3636       case -1:
3637         xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA022"));
3638         statusline(st,1);               // Could not bind socket
3639         break;
3640 
3641       case -2:
3642         xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018"));
3643         statusline(st,1);               // Net Connection timed out
3644         ok = 0;
3645         break;
3646 
3647       default:
3648         break;
3649         /*break;*/
3650     }
3651   }
3652   else if (gai_rc == FAI_TIMEOUT)   /* host lookup time out */
3653   {
3654     xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018"));
3655     statusline(st,1);                       // Net Connection timed out
3656     port_data[port].status = DEVICE_ERROR;
3657     if (debug_level & 2)
3658     {
3659       fprintf(stderr,"Host lookup timeout, port %d, DEVICE_ERROR ***\n",port);
3660     }
3661 
3662     // Show the latest status in the interface control dialog
3663     update_interface_list();
3664 
3665     ok = 0;
3666   }
3667   else        /* Host ip look up failure (no ip address for that host) */
3668   {
3669     xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA023"));
3670     statusline(st,1);                           // No IP for Host
3671     port_data[port].status = DEVICE_ERROR;
3672     if (debug_level & 2)
3673     {
3674       fprintf(stderr,"Host IP lookup failure, port %d, rc %d, DEVICE_ERROR ***\n",port, gai_rc);
3675     }
3676 
3677     // Show the latest status in the interface control dialog
3678     update_interface_list();
3679   }
3680 
3681   if (end_critical_section(&port_data_lock, "interface.c:net_init(10)" ) > 0)
3682   {
3683     fprintf(stderr,"port_data_lock, Port = %d\n", port);
3684   }
3685 
3686   if (debug_level & 2)
3687   {
3688     fprintf(stderr,"*** net_init is returning a %d ***\n",ok);
3689   }
3690 
3691   return(ok);
3692 }
3693 
3694 
3695 
3696 
3697 
3698 //**************************************************************
3699 // This shuts down a network connection
3700 //
3701 //**************************************************************
net_detach(int port)3702 int net_detach(int port)
3703 {
3704   int ok;
3705   int max;
3706   int stat;
3707   char quiti[2];
3708 
3709   if (debug_level & 2)
3710   {
3711     fprintf(stderr,"Net detach Start, port %d\n",port);
3712   }
3713 
3714   ok = -1;
3715   max = 0;
3716 
3717   if (begin_critical_section(&port_data_lock, "interface.c:net_detach(1)" ) > 0)
3718   {
3719     fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port);
3720   }
3721 
3722   if (port_data[port].active == DEVICE_IN_USE)
3723   {
3724     if (port_data[port].status == DEVICE_UP && port_data[port].device_type == DEVICE_NET_STREAM)
3725     {
3726 
3727       if (debug_level & 2)
3728       {
3729         fprintf(stderr,"net_detach():Found port %d up, shutting it down\n",port);
3730       }
3731 
3732       quiti[0] = (char)4;
3733       quiti[1] = (char)0;
3734       if (port_data[port].status == DEVICE_UP)
3735       {
3736         port_write_string(port,quiti);
3737         usleep(100000); // 100ms
3738       }
3739       /* wait to write */
3740       while (port_data[port].status == DEVICE_UP && port_data[port].write_in_pos != port_data[port].write_out_pos && max < 25)
3741       {
3742         if (debug_level & 2)
3743         {
3744           fprintf(stderr,"net_detach():Waiting to finish writing data to port %d\n",port);
3745         }
3746 
3747         usleep(100000);    // 100ms
3748         max++;
3749       }
3750     }
3751     /*
3752       Shut down and Close were separated but this would cause sockets to
3753       just float around
3754     */
3755 
3756     /* we don't need to do a shut down on AX_25 devices */
3757     if ( (port_data[port].status == DEVICE_UP)
3758          && (port_data[port].device_type != DEVICE_AX25_TNC) )
3759     {
3760       stat = shutdown(port_data[port].channel,2);
3761       if (debug_level & 2)
3762       {
3763         fprintf(stderr,"net_detach():Net Shutdown Returned %d, port %d\n",stat,port);
3764       }
3765     }
3766 
3767     usleep(100000); // 100ms
3768     // We wish to close down the socket (so both ends of the darn thing
3769     // go away), but we want to keep the number on those systems that
3770     // re-assign the same file descriptor again.  This is to prevent
3771     // cross-connects from one interface to another in Xastir (big pain!).
3772 
3773     // Close it
3774     stat = close(port_data[port].channel);
3775     if (debug_level & 2)
3776     {
3777       fprintf(stderr,"net_detach():Net Close Returned %d, port %d\n",stat,port);
3778     }
3779 
3780     usleep(100000); // 100ms
3781 
3782     // Snag a socket again.  We'll use it next time around.
3783     port_data[port].channel = socket(PF_INET, SOCK_STREAM, 0);
3784 
3785     ok = 1;
3786   }
3787   /* close down no matter what */
3788   port_data[port].status = DEVICE_DOWN;
3789   //usleep(300);
3790   port_data[port].active = DEVICE_NOT_IN_USE;
3791 
3792   // Show the latest status in the interface control dialog
3793   update_interface_list();
3794 
3795   if (end_critical_section(&port_data_lock, "interface.c:net_detach(2)" ) > 0)
3796   {
3797     fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port);
3798   }
3799 
3800   if (debug_level & 2)
3801   {
3802     fprintf(stderr,"Net detach stop, port %d\n",port);
3803   }
3804 
3805   return(ok);
3806 }
3807 
3808 
3809 
3810 
3811 
3812 //***************************** STOP NETWORK FUNCTIONS **********************************
3813 
3814 
3815 
3816 // This routine changes callsign chars to proper uppercase chars or
3817 // numerals, fixes the callsign to six bytes, shifts the letters left by
3818 // one bit, and puts the SSID number into the proper bits in the seventh
3819 // byte.  The callsign as processed is ready for inclusion in an
3820 // AX.25 header.
3821 //
fix_up_callsign(unsigned char * data,int data_size)3822 void fix_up_callsign(unsigned char *data, int data_size)
3823 {
3824   unsigned char new_call[8] = "       ";  // Start with seven spaces
3825   int ssid = 0;
3826   int i;
3827   int j = 0;
3828   int digipeated_flag = 0;
3829 
3830 
3831   // Check whether we've digipeated through this callsign yet.
3832   if (strstr((const char *)data,"*") != 0)
3833   {
3834     digipeated_flag++;
3835   }
3836 
3837   // Change callsign to upper-case and pad out to six places with
3838   // space characters.
3839   for (i = 0; i < (int)strlen((const char *)data); i++)
3840   {
3841     data[i] = toupper(data[i]);
3842 
3843     if (data[i] == '-')     // Stop at '-'
3844     {
3845       break;
3846     }
3847     else if (data[i] == '*')
3848     {
3849     }
3850     else
3851     {
3852       new_call[j++] = data[i];
3853     }
3854   }
3855   new_call[7] = '\0';
3856 
3857   // Handle SSID.  'i' should now be pointing at a dash or at the
3858   // terminating zero character.
3859   if ( (i < (int)strlen((const char *)data)) && (data[i++] == '-') )     // We might have an SSID
3860   {
3861     if (data[i] != '\0')
3862     {
3863       ssid = atoi((const char *)&data[i]);
3864     }
3865   }
3866 
3867   if (ssid >= 0 && ssid <= 15)
3868   {
3869     new_call[6] = ssid | 0x30;  // Set 2 reserved bits
3870   }
3871   else    // Whacko SSID.  Set it to zero
3872   {
3873     new_call[6] = 0x30;     // Set 2 reserved bits
3874   }
3875 
3876   if (digipeated_flag)
3877   {
3878     new_call[6] = new_call[6] | 0x40; // Set the 'H' bit
3879   }
3880 
3881   // Shift each byte one bit to the left
3882   for (i = 0; i < 7; i++)
3883   {
3884     new_call[i] = new_call[i] << 1;
3885     new_call[i] = new_call[i] & 0xfe;
3886   }
3887 
3888   // Write over the top of the input string with the newly
3889   // formatted callsign
3890   xastir_snprintf((char *)data,
3891                   data_size,
3892                   "%s",
3893                   new_call);
3894 }
3895 
3896 
3897 
3898 
3899 
3900 //-------------------------------------------------------------------
3901 // Had to snag code from port_write_string() below because our string
3902 // needs to have 0x00 chars inside it.  port_write_string() can't
3903 // handle that case.  It's a good thing the transmit queue stuff
3904 // could handle it.
3905 //-------------------------------------------------------------------
3906 //
3907 //WE7U
3908 // Modify the other routines that needed binary output so that they
3909 // use this routine.
3910 //
port_write_binary(int port,unsigned char * data,int length)3911 void port_write_binary(int port, unsigned char *data, int length)
3912 {
3913   int ii,erd;
3914   int write_in_pos_hold;
3915 
3916 
3917   erd = 0;
3918 
3919   if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(1)" ) > 0)
3920   {
3921     fprintf(stderr,"write_lock, Port = %d\n", port);
3922   }
3923 
3924   // Save the current position, just in case we have trouble
3925   write_in_pos_hold = port_data[port].write_in_pos;
3926 
3927   for (ii = 0; ii < length && !erd; ii++)
3928   {
3929 
3930     // Put character into write buffer and advance pointer
3931     port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[ii];
3932 
3933     // Check whether we need to wrap back to the start of the
3934     // circular buffer
3935     if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER)
3936     {
3937       port_data[port].write_in_pos = 0;
3938     }
3939 
3940     // Check whether we just filled our buffer (read/write
3941     // pointers are equal).  If so, exit gracefully, dumping
3942     // this string and resetting the write pointer.
3943     if (port_data[port].write_in_pos == port_data[port].write_out_pos)
3944     {
3945       if (debug_level & 2)
3946       {
3947         fprintf(stderr,"Port %d Buffer overrun\n",port);
3948       }
3949 
3950       // Restore original write_in pos and dump this string
3951       port_data[port].write_in_pos = write_in_pos_hold;
3952       port_data[port].errors++;
3953       erd = 1;
3954     }
3955   }
3956 
3957   if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(2)" ) > 0)
3958   {
3959     fprintf(stderr,"write_lock, Port = %d\n", port);
3960   }
3961 }
3962 
3963 
3964 
3965 
3966 
3967 // Create an AX25 frame and then turn it into a KISS packet.  Dump
3968 // it into the transmit queue.
3969 //
send_ax25_frame(int port,char * source,char * destination,char * path,char * data)3970 void send_ax25_frame(int port, char *source, char *destination, char *path, char *data)
3971 {
3972   unsigned char temp_source[15];
3973   unsigned char temp_dest[15];
3974   unsigned char temp[15];
3975   unsigned char control[2], pid[2];
3976   unsigned char transmit_txt[MAX_LINE_SIZE*2];
3977   unsigned char transmit_txt2[MAX_LINE_SIZE*2];
3978   unsigned char c;
3979   int i, j;
3980   int erd;
3981   int write_in_pos_hold;
3982 
3983 
3984   // Check whether transmits are disabled globally
3985   if (transmit_disable)
3986   {
3987     return;
3988   }
3989 
3990   // Check whether transmit has been enabled for this interface.
3991   // If not, get out while the gettin's good.
3992   if (devices[port].transmit_data != 1)
3993   {
3994     return;
3995   }
3996 
3997   transmit_txt[0] = '\0';
3998 
3999   // Format the destination callsign
4000   xastir_snprintf((char *)temp_dest,
4001                   sizeof(temp_dest),
4002                   "%s",
4003                   destination);
4004   fix_up_callsign(temp_dest, sizeof(temp_dest));
4005   xastir_snprintf((char *)transmit_txt,
4006                   sizeof(transmit_txt),
4007                   "%s",
4008                   temp_dest);
4009 
4010   // Format the source callsign
4011   xastir_snprintf((char *)temp_source,
4012                   sizeof(temp_source),
4013                   "%s",
4014                   source);
4015   fix_up_callsign(temp_source, sizeof(temp_source));
4016   strncat((char *)transmit_txt,
4017           (char *)temp_source,
4018           sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt));
4019 
4020   // Break up the path into individual callsigns and send them one
4021   // by one to fix_up_callsign().  If we get passed an empty path,
4022   // we merely skip this section and no path gets added to
4023   // "transmit_txt".
4024   j = 0;
4025   temp[0] = '\0'; // Start with empty path
4026   if ( (path != NULL) && (strlen(path) != 0) )
4027   {
4028     while (path[j] != '\0')
4029     {
4030       i = 0;
4031       while ( (path[j] != ',') && (path[j] != '\0') )
4032       {
4033         temp[i++] = path[j++];
4034       }
4035       temp[i] = '\0';
4036 
4037       if (path[j] == ',')     // Skip over comma
4038       {
4039         j++;
4040       }
4041 
4042       fix_up_callsign(temp, sizeof(temp));
4043       strncat((char *)transmit_txt,
4044               (char *)temp,
4045               sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt));
4046     }
4047   }
4048 
4049   // Set the end-of-address bit on the last callsign in the
4050   // address field
4051   transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01;
4052 
4053   // Add the Control byte
4054   control[0] = 0x03;
4055   control[1] = '\0';
4056   strncat((char *)transmit_txt,
4057           (char *)control,
4058           sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt));
4059 
4060   // Add the PID byte
4061   pid[0] = 0xf0;
4062   pid[1] = '\0';
4063   strncat((char *)transmit_txt,
4064           (char *)pid,
4065           sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt));
4066 
4067   // Append the information chars
4068   strncat((char *)transmit_txt,
4069           data,
4070           sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt));
4071 
4072   // Add the KISS framing characters and do the proper escapes.
4073   j = 0;
4074   transmit_txt2[j++] = KISS_FEND;
4075 
4076   // Note:  This byte is where different interfaces would be
4077   // specified:
4078   transmit_txt2[j++] = 0x00;
4079 
4080   for (i = 0; i < (int)strlen((const char *)transmit_txt); i++)
4081   {
4082     c = transmit_txt[i];
4083     if (c == KISS_FEND)
4084     {
4085       transmit_txt2[j++] = KISS_FESC;
4086       transmit_txt2[j++] = KISS_TFEND;
4087     }
4088     else if (c == KISS_FESC)
4089     {
4090       transmit_txt2[j++] = KISS_FESC;
4091       transmit_txt2[j++] = KISS_TFESC;
4092     }
4093     else
4094     {
4095       transmit_txt2[j++] = c;
4096     }
4097   }
4098   transmit_txt2[j++] = KISS_FEND;
4099 
4100   // Terminate the string, but don't increment the 'j' counter.
4101   // We don't want to send the NULL byte out the KISS interface,
4102   // just make sure the string is terminated in all cases.
4103   //
4104   transmit_txt2[j] = '\0';
4105 
4106   //-------------------------------------------------------------------
4107   // Had to snag code from port_write_string() below because our string
4108   // needs to have 0x00 chars inside it.  port_write_string() can't
4109   // handle that case.  It's a good thing the transmit queue stuff
4110   // could handle it.
4111   //-------------------------------------------------------------------
4112 
4113   erd = 0;
4114 
4115   if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(1)" ) > 0)
4116   {
4117     fprintf(stderr,"write_lock, Port = %d\n", port);
4118   }
4119 
4120   write_in_pos_hold = port_data[port].write_in_pos;
4121 
4122   for (i = 0; i < j && !erd; i++)
4123   {
4124     port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt2[i];
4125     if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER)
4126     {
4127       port_data[port].write_in_pos = 0;
4128     }
4129 
4130     if (port_data[port].write_in_pos == port_data[port].write_out_pos)
4131     {
4132       if (debug_level & 2)
4133       {
4134         fprintf(stderr,"Port %d Buffer overrun\n",port);
4135       }
4136 
4137       /* clear this restore original write_in pos and dump this string */
4138       port_data[port].write_in_pos = write_in_pos_hold;
4139       port_data[port].errors++;
4140       erd = 1;
4141     }
4142   }
4143 
4144   if (end_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(2)" ) > 0)
4145   {
4146     fprintf(stderr,"write_lock, Port = %d\n", port);
4147   }
4148 }
4149 
4150 
4151 
4152 
4153 
4154 // Send a KISS configuration command to the selected port.
4155 // The KISS spec allows up to 16 devices to be configured.  We
4156 // support that here with the "device" input, which should be
4157 // between 0 and 15.  The commands accepted are integer values:
4158 //
4159 // 0x01 TXDELAY
4160 // 0x02 P-Persistence
4161 // 0x03 SlotTime
4162 // 0x04 TxTail
4163 // 0x05 FullDuplex
4164 // 0x06 SetHardware
4165 // 0xff Exit from KISS mode (not implemented yet)
4166 //
send_kiss_config(int port,int device,int command,int value)4167 void send_kiss_config(int port, int device, int command, int value)
4168 {
4169   unsigned char transmit_txt[MAX_LINE_SIZE+1];
4170   int i, j;
4171   int erd;
4172   int write_in_pos_hold;
4173 
4174 
4175   if (device < 0 || device > 15)
4176   {
4177     fprintf(stderr,"send_kiss_config: out-of-range value for device\n");
4178     return;
4179   }
4180 
4181   if (command < 1 || command > 6)
4182   {
4183     fprintf(stderr,"send_kiss_config: out-of-range value for command\n");
4184     return;
4185   }
4186 
4187   if (value < 0 || value > 255)
4188   {
4189     fprintf(stderr,"send_kiss_config: out-of-range value for value\n");
4190     return;
4191   }
4192 
4193   // Add the KISS framing characters and do the proper escapes.
4194   j = 0;
4195   transmit_txt[j++] = KISS_FEND;
4196 
4197   transmit_txt[j++] = (device << 4) | (command & 0x0f);
4198 
4199   transmit_txt[j++] = value & 0xff;
4200 
4201   transmit_txt[j++] = KISS_FEND;
4202 
4203   // Terminate the string, but don't increment the 'j' counter.
4204   // We don't want to send the NULL byte out the KISS interface,
4205   // just make sure the string is terminated in all cases.
4206   //
4207   transmit_txt[j] = '\0';
4208 
4209 
4210 
4211 
4212   //-------------------------------------------------------------------
4213   // Had to snag code from port_write_string() below because our string
4214   // needs to have 0x00 chars inside it.  port_write_string() can't
4215   // handle that case.  It's a good thing the transmit queue stuff
4216   // could handle it.
4217   //-------------------------------------------------------------------
4218 
4219   erd = 0;
4220 
4221   if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(1)" ) > 0)
4222   {
4223     fprintf(stderr,"write_lock, Port = %d\n", port);
4224   }
4225 
4226   write_in_pos_hold = port_data[port].write_in_pos;
4227 
4228   for (i = 0; i < j && !erd; i++)
4229   {
4230     port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt[i];
4231     if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER)
4232     {
4233       port_data[port].write_in_pos = 0;
4234     }
4235 
4236     if (port_data[port].write_in_pos == port_data[port].write_out_pos)
4237     {
4238       if (debug_level & 2)
4239       {
4240         fprintf(stderr,"Port %d Buffer overrun\n",port);
4241       }
4242 
4243       /* clear this restore original write_in pos and dump this string */
4244       port_data[port].write_in_pos = write_in_pos_hold;
4245       port_data[port].errors++;
4246       erd = 1;
4247     }
4248   }
4249 
4250   if (end_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(2)" ) > 0)
4251   {
4252     fprintf(stderr,"write_lock, Port = %d\n", port);
4253   }
4254 }
4255 
4256 
4257 
4258 
4259 
4260 //***********************************************************
4261 // port_write_string()
4262 //
4263 // port is port# used
4264 // data is the string to write
4265 //***********************************************************
4266 
port_write_string(int port,char * data)4267 void port_write_string(int port, char *data)
4268 {
4269   int i,erd;
4270   int write_in_pos_hold;
4271 
4272   if (data == NULL)
4273   {
4274     return;
4275   }
4276 
4277   if (data[0] == '\0')
4278   {
4279     return;
4280   }
4281 
4282   erd = 0;
4283 
4284   if (debug_level & 2)
4285   {
4286     fprintf(stderr,"CMD:%s\n",data);
4287   }
4288 
4289   if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(1)" ) > 0)
4290   {
4291     fprintf(stderr,"write_lock, Port = %d\n", port);
4292   }
4293 
4294   write_in_pos_hold = port_data[port].write_in_pos;
4295 
4296   // Normal Serial/Net output?
4297   if (port_data[port].device_type != DEVICE_AX25_TNC)
4298   {
4299     for (i = 0; i < (int)strlen(data) && !erd; i++)
4300     {
4301       port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[i];
4302       if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER)
4303       {
4304         port_data[port].write_in_pos = 0;
4305       }
4306 
4307       if (port_data[port].write_in_pos == port_data[port].write_out_pos)
4308       {
4309         if (debug_level & 2)
4310         {
4311           fprintf(stderr,"Port %d Buffer overrun\n",port);
4312         }
4313 
4314         /* clear this restore original write_in pos and dump this string */
4315         port_data[port].write_in_pos = write_in_pos_hold;
4316         port_data[port].errors++;
4317         erd = 1;
4318       }
4319     }
4320   }
4321 
4322   // AX.25 port output
4323   else
4324   {
4325     port_data[port].bytes_output += strlen(data);
4326     data_out_ax25(port,(unsigned char *)data);
4327     /* do for interface indicators */
4328     if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER)
4329     {
4330       port_data[port].write_in_pos = 0;
4331     }
4332   }
4333 
4334   if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(2)" ) > 0)
4335   {
4336     fprintf(stderr,"write_lock, Port = %d\n", port);
4337   }
4338 }
4339 
4340 
4341 
4342 
4343 
4344 //***********************************************************
4345 // port_read()
4346 //
4347 // port is port# used
4348 //
4349 // This function becomes the long-running thread that snags
4350 // characters from an interface and passes them off to the
4351 // decoding routines.  One copy of this is run for each read
4352 // thread for each interface.
4353 //***********************************************************
4354 
port_read(int port)4355 void port_read(int port)
4356 {
4357   unsigned char cin;
4358   unsigned char buffer[MAX_DEVICE_BUFFER];    // Only used for AX.25 packets
4359   int i;
4360   struct timeval tmv;
4361   fd_set rd;
4362   int group;
4363   int binary_wx_data = 0;
4364   int max;
4365   /*
4366    * Some local variables used for checking AX.25 data - PE1DNN
4367    *
4368    * "from"     is used to look up where the data comes from
4369    * "from_len" is used to keep the size of sockaddr structure
4370    * "dev"      is used to keep the name of the interface that
4371    *            belongs to our port/device_name
4372    */
4373   struct sockaddr from;
4374   socklen_t from_len;
4375 
4376 #ifdef HAVE_LIBAX25
4377   char           *dev;
4378 #endif /* USE_AX25 */
4379 
4380   if (debug_level & 2)
4381   {
4382     fprintf(stderr,"Port %d read start\n",port);
4383   }
4384 
4385   group = 0;
4386   max = MAX_DEVICE_BUFFER - 1;
4387   cin = (unsigned char)0;
4388 
4389   // We stay in this read loop until the port is shut down
4390   while(port_data[port].active == DEVICE_IN_USE)
4391   {
4392 
4393     if (port_data[port].status == DEVICE_UP)
4394     {
4395 
4396       port_data[port].read_in_pos = 0;
4397       port_data[port].scan = 1;
4398 
4399       while (port_data[port].scan
4400              && (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) )
4401              && (port_data[port].status == DEVICE_UP) )
4402       {
4403 
4404         int skip = 0;
4405 
4406         // Handle all EXCEPT AX25_TNC interfaces here
4407         if (port_data[port].device_type != DEVICE_AX25_TNC)
4408         {
4409           // Get one character
4410           port_data[port].scan = (int)read(port_data[port].channel,&cin,1);
4411         }
4412 
4413         else    // Handle AX25_TNC interfaces
4414         {
4415           /*
4416            * Use recvfrom on a network socket to know from
4417            * which interface the packet came - PE1DNN
4418            */
4419 
4420 #ifdef __solaris__
4421           from_len = (unsigned int)sizeof(from);
4422 #else   // __solaris__
4423           from_len = (socklen_t)sizeof(from);
4424 #endif  // __solaris__
4425 
4426           port_data[port].scan = recvfrom(port_data[port].channel,buffer,
4427                                           sizeof(buffer) - 1,
4428                                           0,
4429                                           &from,
4430                                           &from_len);
4431         }
4432 
4433 
4434         // Below is code for ALL types of interfaces
4435         if (port_data[port].scan > 0 && port_data[port].status == DEVICE_UP )
4436         {
4437 
4438           if (port_data[port].device_type != DEVICE_AX25_TNC)
4439           {
4440             port_data[port].bytes_input += port_data[port].scan;  // Add character to read buffer
4441           }
4442 
4443           // Handle all EXCEPT AX25_TNC interfaces here
4444           if (port_data[port].device_type != DEVICE_AX25_TNC)
4445           {
4446 
4447 
4448             // Do special KISS packet processing here.
4449             // We save the last character in
4450             // port_data[port].channel2, as it is
4451             // otherwise only used for AX.25 ports.
4452 
4453             if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC)
4454                  || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) )
4455             {
4456 
4457 
4458               if (port_data[port].channel2 == KISS_FESC)   // Frame Escape char
4459               {
4460                 if (cin == KISS_TFEND)   // Transposed Frame End char
4461                 {
4462 
4463                   // Save this char for next time
4464                   // around
4465                   port_data[port].channel2 = cin;
4466 
4467                   cin = KISS_FEND;
4468                 }
4469                 else if (cin == KISS_TFESC)   // Transposed Frame Escape char
4470                 {
4471 
4472                   // Save this char for next time
4473                   // around
4474                   port_data[port].channel2 = cin;
4475 
4476                   cin = KISS_FESC;
4477                 }
4478                 else
4479                 {
4480                   port_data[port].channel2 = cin;
4481                 }
4482               }
4483               else if (port_data[port].channel2 == KISS_FEND)   // Frame End char
4484               {
4485                 // Frame start or frame end.  Drop
4486                 // the next character which should
4487                 // either be another frame end or a
4488                 // type byte.
4489 
4490                 // Note this "type" byte is where it specifies which KISS interface
4491                 // the packet came from.  We may want to use this later for
4492                 // multi-drop KISS or other types of KISS protocols.
4493 
4494                 // Save this char for next time
4495                 // around
4496                 port_data[port].channel2 = cin;
4497                 skip++;
4498               }
4499               else if (cin == KISS_FESC)   // Frame Escape char
4500               {
4501                 port_data[port].channel2 = cin;
4502                 skip++;
4503               }
4504               else
4505               {
4506                 port_data[port].channel2 = cin;
4507               }
4508             }   // End of first special KISS processing
4509 
4510 
4511 
4512 
4513 
4514             // AGWPE
4515             // Process AGWPE packets here.  Massage the frames so that they look
4516             // like normal serial packets to the Xastir decoding functions?
4517             //
4518             // We turn on monitoring of packets when we first connect.  We now
4519             // need to throw away all but the "U" packets, which are unconnected
4520             // information packets.
4521             //
4522             // Check for enough bytes to complete a header (36 bytes).  If
4523             // enough, check the datalength to see if an entire packet has been
4524             // read.  If so, run that packet through a conversion routine to
4525             // convert it to a TAPR2-style packet.
4526             //
4527             // Right now we're not taking into account multiple radio ports that
4528             // AGWPE is capable of.  Just assume that we'll receive from all
4529             // radio ports, but transmit out port 0.
4530             //
4531             if (port_data[port].device_type == DEVICE_NET_AGWPE)
4532             {
4533               int bytes_available = 0;
4534               long frame_length = 0;
4535 
4536 
4537               skip = 1;   // Keeps next block of code from
4538               // trying to process this data.
4539 
4540               // Add it to the buffer
4541               if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) )
4542               {
4543                 port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin;
4544                 port_data[port].read_in_pos++;
4545                 port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0;
4546               }
4547               else
4548               {
4549                 if (debug_level & 2)
4550                 {
4551                   fprintf(stderr,"Port read overrun (1) on %d\n",port);
4552                 }
4553 
4554                 port_data[port].read_in_pos = 0;
4555               }
4556 
4557               bytes_available = port_data[port].read_in_pos - port_data[port].read_out_pos;
4558               if (bytes_available < 0)
4559               {
4560                 bytes_available = (bytes_available + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER;
4561               }
4562 
4563               if (bytes_available >= 36)
4564               {
4565                 // We have a full AGWPE header,
4566                 // which means we can compute the
4567                 // frame length.
4568                 unsigned char count[4];
4569                 int my_pointer;
4570 
4571                 // Snag bytes 28-32 of the buffer and compute frame_length
4572                 my_pointer = (port_data[port].read_out_pos + 28) % MAX_DEVICE_BUFFER;
4573                 count[0] = (unsigned char)port_data[port].device_read_buffer[my_pointer];
4574                 my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER;
4575                 count[1] = (unsigned char)port_data[port].device_read_buffer[my_pointer];
4576                 my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER;
4577                 count[2] = (unsigned char)port_data[port].device_read_buffer[my_pointer];
4578                 my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER;
4579                 count[3] = (unsigned char)port_data[port].device_read_buffer[my_pointer];
4580 
4581                 frame_length = 0;
4582                 frame_length = frame_length | (count[0]      );
4583                 frame_length = frame_length | (count[1] <<  8);
4584                 frame_length = frame_length | (count[2] << 16);
4585                 frame_length = frame_length | (count[3] << 24);
4586 
4587                 // Have a complete AGWPE packet?  If
4588                 // so, convert it to a more standard
4589                 // packet format then feed it to our
4590                 // decoding routines.
4591                 //
4592                 if (bytes_available >= (frame_length+36))
4593                 {
4594                   char input_string[MAX_DEVICE_BUFFER];
4595                   char output_string[MAX_DEVICE_BUFFER];
4596                   int ii,jj,new_length;
4597 
4598                   my_pointer = port_data[port].read_out_pos;
4599                   jj = 0;
4600                   for (ii = 0; ii < frame_length+36; ii++)
4601                   {
4602                     input_string[jj++] = (unsigned char)port_data[port].device_read_buffer[my_pointer];
4603                     my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER;
4604                   }
4605 
4606                   // Add a terminator.  We need
4607                   // this for the raw packets so
4608                   // that we don't end up getting
4609                   // portions of strings
4610                   // concatenated onto the end of
4611                   // our current packet during
4612                   // later processing.
4613                   input_string[jj] = '\0';
4614 
4615                   my_pointer = port_data[port].read_out_pos;
4616 
4617                   if ( parse_agwpe_packet((unsigned char *)input_string,
4618                                           frame_length+36,
4619                                           (unsigned char *)output_string,
4620                                           &new_length) )
4621                   {
4622                     channel_data(port,
4623                                  (unsigned char *)output_string,
4624                                  new_length+1); // include terminator
4625                   }
4626 
4627                   for (i = 0; i <= port_data[port].read_in_pos; i++)
4628                   {
4629                     port_data[port].device_read_buffer[i] = (char)0;
4630                   }
4631 
4632                   port_data[port].read_in_pos = 0;
4633                 }
4634               }
4635               else
4636               {
4637                 // Not enough for a full header so
4638                 // we can't compute frame length
4639                 // yet.  Do nothing until we have
4640                 // more data.
4641               }
4642             }
4643             // End of new AGWPE code
4644 
4645 
4646 
4647             // We shouldn't see any AX.25 flag
4648             // characters on a KISS interface because
4649             // they are stripped out by the KISS code.
4650             // What we should see though are KISS_FEND
4651             // characters at the beginning of each
4652             // packet.  These characters are where we
4653             // should break the data apart in order to
4654             // send strings to the decode routines.  It
4655             // may be just fine to still break it on \r
4656             // or \n chars, as the KISS_FEND should
4657             // appear immediately afterwards in
4658             // properly formed packets.
4659 
4660 
4661             if ( (!skip)
4662                  && (cin == (unsigned char)'\r'
4663                      || cin == (unsigned char)'\n'
4664                      || port_data[port].read_in_pos >= (MAX_DEVICE_BUFFER - 1)
4665                      || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) )
4666                      || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) )
4667                  && port_data[port].data_type == 0)       // If end-of-line
4668             {
4669 
4670               // End serial/net type data send it to the decoder Put a terminating
4671               // zero at the end of the read-in data
4672 
4673               port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0;
4674 
4675               if (port_data[port].status == DEVICE_UP && port_data[port].read_in_pos > 0)
4676               {
4677                 int length;
4678 
4679                 // Compute length of string in
4680                 // circular queue
4681 
4682                 // KISS TNC sends binary data
4683                 if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC)
4684                      || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) )
4685                 {
4686 
4687                   length = port_data[port].read_in_pos - port_data[port].read_out_pos;
4688                   if (length < 0)
4689                   {
4690                     length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER;
4691                   }
4692 
4693                   length++;
4694                 }
4695                 else    // ASCII data
4696                 {
4697                   length = 0;
4698                 }
4699 
4700                 channel_data(port,
4701                              (unsigned char *)port_data[port].device_read_buffer,
4702                              length);   // Length of string
4703               }
4704 
4705               for (i = 0; i <= port_data[port].read_in_pos; i++)
4706               {
4707                 port_data[port].device_read_buffer[i] = (char)0;
4708               }
4709 
4710               port_data[port].read_in_pos = 0;
4711             }
4712             else if (!skip)
4713             {
4714 
4715               // Check for binary WX station data
4716               if (port_data[port].data_type == 1 && (port_data[port].device_type == DEVICE_NET_WX ||
4717                                                      port_data[port].device_type == DEVICE_SERIAL_WX))
4718               {
4719 
4720                 /* BINARY DATA input (WX data ?) */
4721                 /* check RS WX200 */
4722                 switch (cin)
4723                 {
4724 
4725                   case 0x8f:
4726                   case 0x9f:
4727                   case 0xaf:
4728                   case 0xbf:
4729                   case 0xcf:
4730 
4731                     if (group == 0)
4732                     {
4733                       port_data[port].read_in_pos = 0;
4734                       group = (int)cin;
4735                       switch (cin)
4736                       {
4737 
4738                         case 0x8f:
4739                           max = 35;
4740                           binary_wx_data = 1;
4741                           break;
4742 
4743                         case 0x9f:
4744                           max = 34;
4745                           binary_wx_data = 1;
4746                           break;
4747 
4748                         case 0xaf:
4749                           max = 31;
4750                           binary_wx_data = 1;
4751                           break;
4752 
4753                         case 0xbf:
4754                           max = 14;
4755                           binary_wx_data = 1;
4756                           break;
4757 
4758                         case 0xcf:
4759                           max = 27;
4760                           binary_wx_data = 1;
4761                           break;
4762 
4763                         default:
4764                           break;
4765                       }
4766                     }
4767                     break;
4768 
4769                   default:
4770                     break;
4771                 }
4772                 if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) )
4773                 {
4774                   port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin;
4775                   port_data[port].read_in_pos++;
4776                   port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0;
4777                 }
4778                 else
4779                 {
4780                   if (debug_level & 2)
4781                   {
4782                     fprintf(stderr,"Port read overrun (1) on %d\n",port);
4783                   }
4784 
4785                   port_data[port].read_in_pos = 0;
4786                 }
4787                 if (port_data[port].read_in_pos >= max)
4788                 {
4789                   if (group != 0)     /* ok try to decode it */
4790                   {
4791                     int length = 0;
4792                     if (binary_wx_data)
4793                     {
4794                       length = port_data[port].read_in_pos - port_data[port].read_out_pos;
4795                       if (length < 0)
4796                       {
4797                         length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER;
4798                       }
4799                       length++;
4800                     }
4801 
4802                     channel_data(port,
4803                                  (unsigned char *)port_data[port].device_read_buffer,
4804                                  length);
4805                   }
4806                   max = MAX_DEVICE_BUFFER - 1;
4807                   group = 0;
4808 
4809                   port_data[port].read_in_pos = 0;
4810                 }
4811               }
4812               else   /* Normal Data input */
4813               {
4814 
4815                 if (cin == '\0')    // OWW WX daemon sends 0x00's!
4816                 {
4817                   cin = '\n';
4818                 }
4819 
4820                 if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) )
4821                 {
4822                   port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin;
4823                   port_data[port].read_in_pos++;
4824                   port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0;
4825                 }
4826                 else
4827                 {
4828                   if (debug_level & 2)
4829                   {
4830                     fprintf(stderr,"Port read overrun (2) on %d\n",port);
4831                   }
4832 
4833                   port_data[port].read_in_pos = 0;
4834                 }
4835               }
4836             }
4837 
4838             // Ascii WX station data but no line-ends?
4839             if (port_data[port].read_in_pos > MAX_DEVICE_BUFFER_UNTIL_BINARY_SWITCH &&
4840                 (port_data[port].device_type == DEVICE_NET_WX
4841                  || port_data[port].device_type == DEVICE_SERIAL_WX))
4842             {
4843 
4844               /* normal data on WX not found do look at data for binary WX */
4845               port_data[port].data_type++;
4846               port_data[port].data_type &= 1;
4847               port_data[port].read_in_pos = 0;
4848             }
4849           }   // End of non-AX.25 interface code block
4850 
4851 
4852           else      // Process ax25 interface data and send to the decoder
4853           {
4854             /*
4855              * Only accept data from our own interface (recvfrom will get
4856              * data from all AX.25 interfaces!) - PE1DNN
4857              */
4858 #ifdef HAVE_LIBAX25
4859             if (port_data[port].device_name != NULL)
4860             {
4861               if ((dev = ax25_config_get_dev(port_data[port].device_name)) != NULL)
4862               {
4863                 /* if the data is not from our interface, ignore it! PE1DNN */
4864                 if(strcmp(dev, from.sa_data) == 0)
4865                 {
4866                   /* Received data from our interface! - process data */
4867                   if (process_ax25_packet(buffer,
4868                                           port_data[port].scan,
4869                                           port_data[port].device_read_buffer,
4870                                           sizeof(port_data[port].device_read_buffer)) != NULL)
4871                   {
4872                     port_data[port].bytes_input += strlen(port_data[port].device_read_buffer);
4873 
4874                     channel_data(port,
4875                                  (unsigned char *)port_data[port].device_read_buffer,
4876                                  0);
4877                   }
4878                   /*
4879                     do this for interface indicator in this case we only do it for,
4880                     data from the correct AX.25 port
4881                   */
4882                   if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) )
4883                   {
4884                     port_data[port].read_in_pos += port_data[port].scan;
4885                   }
4886                   else
4887                   {
4888 
4889                     /* no buffer over runs writing a line at a time */
4890                     port_data[port].read_in_pos = 0;
4891                   }
4892                 }
4893               }
4894             }
4895 #endif /* HAVE_LIBAX25 */
4896           }   // End of AX.25 interface code block
4897         }
4898         else if (port_data[port].status == DEVICE_UP)      /* error or close on read */
4899         {
4900           port_data[port].errors++;
4901           if (port_data[port].scan == 0)
4902           {
4903             // Should not get this unless the device is down.  NOT TRUE!
4904             // We seem to also be able to get here if we're closing/restarting
4905             // another interface.  For that reason I commented out the below
4906             // statement so that this interface won't go down.  The inactivity
4907             // timer solves that issue now anyway.  --we7u.
4908             port_data[port].status = DEVICE_ERROR;
4909 
4910             // If the below statement is enabled, it causes an immediate reconnect
4911             // after one time-period of inactivity, currently 7.5 minutes, as set in
4912             // main.c:UpdateTime().  This means the symbol will never change from green
4913             // to red on the status bar, so the operator might not know about a
4914             // connection that is being constantly reconnected.  By leaving it commented
4915             // out we get one time period of red, and then it will reconnect at the 2nd
4916             // time period.  This means we can reconnect within 15 minutes if a line
4917             // goes dead.
4918             //
4919             port_data[port].reconnects = -1;     // Causes an immediate reconnect
4920 
4921             if (debug_level & 2)
4922             {
4923               fprintf(stderr,"end of file on read, or signal interrupted the read, port %d\n",port);
4924             }
4925 
4926             // Show the latest status in the interface control dialog
4927             update_interface_list();
4928 
4929           }
4930           else
4931           {
4932             if (port_data[port].scan == -1)
4933             {
4934               /* Should only get this if an real error occurs */
4935               port_data[port].status = DEVICE_ERROR;
4936 
4937               // If the below statement is enabled, it causes an immediate reconnect
4938               // after one time-period of inactivity, currently 7.5 minutes, as set in
4939               // main.c:UpdateTime().  This means the symbol will never change from green
4940               // to red on the status bar, so the operator might not know about a
4941               // connection that is being constantly reconnected.  By leaving it commented
4942               // out we get one time period of red, and then it will reconnect at the 2nd
4943               // time period.  This means we can reconnect within 15 minutes if a line
4944               // goes dead.
4945               //
4946               port_data[port].reconnects = -1;     // Causes an immediate reconnect
4947 
4948               // Show the latest status in the
4949               // interface control dialog
4950               update_interface_list();
4951 
4952               if (debug_level & 2)
4953               {
4954                 fprintf(stderr,"error on read with error no %d, or signal interrupted the read, port %d, DEVICE_ERROR ***\n",
4955                         errno,port);
4956                 switch (errno)
4957                 {
4958 
4959                   case EINTR:
4960                     fprintf(stderr,"EINTR ERROR\n");
4961                     break;
4962 
4963                   case EAGAIN:
4964                     fprintf(stderr,"EAGAIN ERROR\n");
4965                     break;
4966 
4967                   case EIO:
4968                     fprintf(stderr,"EIO ERROR\n");
4969                     break;
4970 
4971                   case EISDIR:
4972                     fprintf(stderr,"EISDIR ERROR\n");
4973                     break;
4974 
4975                   case EBADF: // Get this one when we terminate nearby threads
4976                     fprintf(stderr,"EBADF ERROR\n");
4977                     break;
4978 
4979                   case EINVAL:
4980                     fprintf(stderr,"EINVAL ERROR\n");
4981                     break;
4982 
4983                   case EFAULT:
4984                     fprintf(stderr,"EFAULT ERROR\n");
4985                     break;
4986 
4987                   default:
4988                     fprintf(stderr,"OTHER ERROR\n");
4989                     break;
4990                 }
4991               }
4992             }
4993           }
4994         }
4995       }
4996     }
4997     if (port_data[port].active == DEVICE_IN_USE)
4998     {
4999 
5000       // We need to delay here so that the thread doesn't use
5001       // high amounts of CPU doing nothing.
5002 
5003       // This select that waits on data and a timeout, so that if data
5004       // doesn't come in within a certain period of time, we wake up to
5005       // check whether the socket has gone down.  Else, we go back into
5006       // the select to wait for more data or a timeout.  FreeBSD has a
5007       // problem if this is less than 1ms.  Linux works ok down to 100us.
5008       // We don't need it anywhere near that short though.  We just need
5009       // to check whether the main thread has requested the interface be
5010       // closed, and so need to have this short enough to have reasonable
5011       // response time to the user.
5012 
5013       // Set up the select to block until data ready or 100ms
5014       // timeout, whichever occurs first.
5015       FD_ZERO(&rd);
5016       FD_SET(port_data[port].channel, &rd);
5017       tmv.tv_sec = 0;
5018       tmv.tv_usec = 100000;    // 100 ms
5019       (void)select(0,&rd,NULL,NULL,&tmv);
5020     }
5021   }
5022 
5023   if (debug_level & 2)
5024   {
5025     fprintf(stderr,"Thread for port %d read down!\n",port);
5026   }
5027 }
5028 
5029 
5030 
5031 
5032 
5033 //***********************************************************
5034 // port_write()
5035 //
5036 // port is port# used
5037 //
5038 // This function becomes the long-running thread that sends
5039 // characters to an interface.  One copy of this is run for
5040 // each write thread for each interface.
5041 //***********************************************************
port_write(int port)5042 void port_write(int port)
5043 {
5044   int retval;
5045   struct timeval tmv;
5046   fd_set wd;
5047   int wait_max;
5048   unsigned long bytes_input;
5049   char write_buffer[MAX_DEVICE_BUFFER];
5050   int quantity;
5051 
5052 
5053   if (debug_level & 2)
5054   {
5055     fprintf(stderr,"Port %d write start\n",port);
5056   }
5057 
5058   init_critical_section(&port_data[port].write_lock);
5059 
5060   while(port_data[port].active == DEVICE_IN_USE)
5061   {
5062 
5063     if (port_data[port].status == DEVICE_UP)
5064     {
5065       // Some messiness necessary because we're using
5066       // xastir_mutex's instead of pthread_mutex_t's.
5067       pthread_mutex_t *cleanup_mutex;
5068 
5069 
5070       // Install the cleanup routine for the case where this
5071       // thread gets killed while the mutex is locked.  The
5072       // cleanup routine initiates an unlock before the thread
5073       // dies.  We must be in deferred cancellation mode for
5074       // the thread to have this work properly.  We must first
5075       // get the pthread_mutex_t address:
5076       cleanup_mutex = &port_data[port].write_lock.lock;
5077 
5078       // Then install the cleanup routine:
5079       pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex);
5080 
5081 
5082       if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write(1)" ) > 0)
5083       {
5084         fprintf(stderr,"write_lock, Port = %d\n", port);
5085       }
5086 
5087       if ( (port_data[port].write_in_pos != port_data[port].write_out_pos)
5088            && port_data[port].status == DEVICE_UP)
5089       {
5090         // We have something in the buffer to transmit!
5091 
5092 
5093         // Handle control-C delay
5094         switch (port_data[port].device_type)
5095         {
5096 
5097           // Use this block for serial interfaces where we
5098           // need special delays for control-C character
5099           // processing in the TNC.
5100           case DEVICE_SERIAL_TNC_HSP_GPS:
5101           case DEVICE_SERIAL_TNC_AUX_GPS:
5102           case DEVICE_SERIAL_TNC:
5103 
5104             // Are we trying to send a control-C?  If so, wait a
5105             // special amount of time _before_ we send
5106             // it out the serial port.
5107             if (port_data[port].device_write_buffer[port_data[port].write_out_pos] == (char)0x03)
5108             {
5109               // Sending control-C.
5110 
5111               if (debug_level & 128)
5112               {
5113                 fprintf(stderr,"Writing command [%x] on port %d, at pos %d\n",
5114                         *(port_data[port].device_write_buffer +
5115                           port_data[port].write_out_pos),
5116                         port, port_data[port].write_out_pos);
5117               }
5118 
5119               wait_max = 0;
5120               bytes_input = port_data[port].bytes_input + 40;
5121               while ( (port_data[port].bytes_input != bytes_input)
5122                       && (port_data[port].status == DEVICE_UP)
5123                       && (wait_max < 100) )
5124               {
5125                 bytes_input = port_data[port].bytes_input;
5126 
5127                 /*wait*/
5128                 FD_ZERO(&wd);
5129                 FD_SET(port_data[port].channel, &wd);
5130                 tmv.tv_sec = 0;
5131                 tmv.tv_usec = 80000l;   // Delay 80ms
5132                 (void)select(0,NULL,&wd,NULL,&tmv);
5133                 wait_max++;
5134               }
5135             }   // End of command byte wait
5136             break;
5137 
5138           // Use this block for all other interfaces.
5139           default:
5140             // Do nothing (no delays for control-C's)
5141             break;
5142 
5143         }   // End of switch
5144         // End of control-C delay code
5145 
5146 
5147         pthread_testcancel();   // Check for thread termination request
5148 
5149 
5150         // Handle method of sending data (1 or multiple chars per TX)
5151         switch (port_data[port].device_type)
5152         {
5153 
5154           // Use this block for serial interfaces where we
5155           // need character pacing and so must send one
5156           // character per write.
5157           case DEVICE_SERIAL_TNC_HSP_GPS:
5158           case DEVICE_SERIAL_TNC_AUX_GPS:
5159           case DEVICE_SERIAL_KISS_TNC:
5160           case DEVICE_SERIAL_MKISS_TNC:
5161           case DEVICE_SERIAL_TNC:
5162           case DEVICE_SERIAL_GPS:
5163           case DEVICE_SERIAL_WX:
5164             // Do the actual write here, one character
5165             // at a time for these types of interfaces.
5166 
5167             retval = (int)write(port_data[port].channel,
5168                                 &port_data[port].device_write_buffer[port_data[port].write_out_pos],
5169                                 1);
5170 
5171             pthread_testcancel();   // Check for thread termination request
5172 
5173             if (retval == 1)    // We succeeded in writing one byte
5174             {
5175 
5176               port_data[port].bytes_output++;
5177 
5178               port_data[port].write_out_pos++;
5179               if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER)
5180               {
5181                 port_data[port].write_out_pos = 0;
5182               }
5183 
5184             }
5185             else
5186             {
5187               /* error of some kind */
5188               port_data[port].errors++;
5189               port_data[port].status = DEVICE_ERROR;
5190 
5191               // If the below statement is enabled, it causes an immediate reconnect
5192               // after one time-period of inactivity, currently 7.5 minutes, as set in
5193               // main.c:UpdateTime().  This means the symbol will never change from green
5194               // to red on the status bar, so the operator might not know about a
5195               // connection that is being constantly reconnected.  By leaving it commented
5196               // out we get one time period of red, and then it will reconnect at the 2nd
5197               // time period.  This means we can reconnect within 15 minutes if a line
5198               // goes dead.
5199               //
5200               port_data[port].reconnects = -1;     // Causes an immediate reconnect
5201 
5202               if (retval == 0)
5203               {
5204                 /* Should not get this unless the device is down */
5205                 if (debug_level & 2)
5206                 {
5207                   fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port);
5208                 }
5209               }
5210               else
5211               {
5212                 if (retval == -1)
5213                 {
5214                   /* Should only get this if an real error occurs */
5215                   if (debug_level & 2)
5216                   {
5217                     fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port);
5218                   }
5219                 }
5220               }
5221               // Show the latest status in the interface control dialog
5222               update_interface_list();
5223             }
5224             if (serial_char_pacing > 0)
5225             {
5226               // Character pacing.  Delay in between
5227               // each character in milliseconds.
5228               // Convert to microseconds for this
5229               // usleep() call .
5230               usleep(serial_char_pacing * 1000);
5231             }
5232             break;
5233 
5234           // Use this block for all other interfaces where
5235           // we don't need character pacing and we can
5236           // send blocks of data in one write.
5237           default:
5238             // Do the actual write here, one buffer's
5239             // worth at a time.
5240 
5241             // Copy the data to a linear write buffer so
5242             // that we can send it all in one shot.
5243 
5244             // Need to handle the case where only a portion of the data was
5245             // written by the write() function.  Perhaps just write out an error
5246             // message?
5247             quantity = 0;
5248             while (port_data[port].write_in_pos != port_data[port].write_out_pos)
5249             {
5250 
5251               write_buffer[quantity] = port_data[port].device_write_buffer[port_data[port].write_out_pos];
5252 
5253               port_data[port].write_out_pos++;
5254               if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER)
5255               {
5256                 port_data[port].write_out_pos = 0;
5257               }
5258 
5259               quantity++;
5260             }
5261 
5262             retval = (int)write(port_data[port].channel,
5263                                 write_buffer,
5264                                 quantity);
5265 
5266             pthread_testcancel();   // Check for thread termination request
5267 
5268             if (retval == quantity)    // We succeeded in writing one byte
5269             {
5270               port_data[port].bytes_output++;
5271             }
5272             else
5273             {
5274               /* error of some kind */
5275               port_data[port].errors++;
5276               port_data[port].status = DEVICE_ERROR;
5277 
5278               // If the below statement is enabled, it causes an immediate reconnect
5279               // after one time-period of inactivity, currently 7.5 minutes, as set in
5280               // main.c:UpdateTime().  This means the symbol will never change from green
5281               // to red on the status bar, so the operator might not know about a
5282               // connection that is being constantly reconnected.  By leaving it commented
5283               // out we get one time period of red, and then it will reconnect at the 2nd
5284               // time period.  This means we can reconnect within 15 minutes if a line
5285               // goes dead.
5286               //
5287               port_data[port].reconnects = -1;     // Causes an immediate reconnect
5288 
5289               if (retval == 0)
5290               {
5291                 /* Should not get this unless the device is down */
5292                 if (debug_level & 2)
5293                 {
5294                   fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port);
5295                 }
5296               }
5297               else
5298               {
5299                 if (retval == -1)
5300                 {
5301                   /* Should only get this if an real error occurs */
5302                   if (debug_level & 2)
5303                   {
5304                     fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port);
5305                   }
5306                 }
5307               }
5308               // Show the latest status in the interface control dialog
5309               update_interface_list();
5310             }
5311             break;
5312 
5313         }   // End of switch
5314         // End of handling method of sending data (1 or multiple char per TX)
5315 
5316 
5317       }
5318 
5319       if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write(2)" ) > 0)
5320       {
5321         fprintf(stderr,"write_lock, Port = %d\n", port);
5322       }
5323 
5324       // Remove the cleanup routine for the case where this
5325       // thread gets killed while the mutex is locked.  The
5326       // cleanup routine initiates an unlock before the thread
5327       // dies.  We must be in deferred cancellation mode for
5328       // the thread to have this work properly.
5329       //
5330       pthread_cleanup_pop(0);
5331     }
5332 
5333     if (port_data[port].active == DEVICE_IN_USE)
5334     {
5335 
5336       // Delay here so that the thread doesn't use high
5337       // amounts of CPU doing _nothing_.  Take this delay out
5338       // and the thread will take lots of CPU time.
5339 
5340       // Try to change this to a select that waits on data and a timeout,
5341       // so that if data doesn't come in within a certain period of time,
5342       // we wake up to check whether the socket has gone down.  Else, we
5343       // go back into the select to wait for more data or a timeout.
5344       // FreeBSD has a problem if this is less than 1ms.  Linux works ok
5345       // down to 100us.  Theoretically we don't need it anywhere near that
5346       // short, we just need to check whether the main thread has
5347       // requested the interface be closed, and so need to have this short
5348       // enough to have reasonable response time to the user.
5349       // Unfortunately it has been reported that having this at 100ms
5350       // causes about 9 seconds of delay when transmitting to a KISS TNC,
5351       // so it's good to keep this short also.
5352 
5353       FD_ZERO(&wd);
5354       FD_SET(port_data[port].channel, &wd);
5355       tmv.tv_sec = 0;
5356       tmv.tv_usec = 2000;  // Delay 2ms
5357       (void)select(0,NULL,&wd,NULL,&tmv);
5358     }
5359   }
5360   if (debug_level & 2)
5361   {
5362     fprintf(stderr,"Thread for port %d write down!\n",port);
5363   }
5364 }
5365 
5366 
5367 
5368 
5369 
5370 //***********************************************************
5371 // read_access_port_thread()
5372 //
5373 // Port read thread.
5374 // port is port# used
5375 //
5376 // open threads for reading data from this port.
5377 //***********************************************************
read_access_port_thread(void * arg)5378 static void* read_access_port_thread(void *arg)
5379 {
5380   int port;
5381 
5382   port = *((int *) arg);
5383   // This call means we don't care about the return code and won't
5384   // use pthread_join() later.  Makes threading more efficient.
5385   (void)pthread_detach(pthread_self());
5386   port_read(port);
5387 
5388   return(NULL);
5389 }
5390 
5391 
5392 
5393 
5394 
5395 //***********************************************************
5396 // write_access_port_thread()
5397 //
5398 // Port write thread.
5399 // port is port# used
5400 //
5401 // open threads for writing data to this port.
5402 //***********************************************************
write_access_port_thread(void * arg)5403 static void* write_access_port_thread(void *arg)
5404 {
5405   int port;
5406 
5407   port = *((int *) arg);
5408   // This call means we don't care about the return code and won't
5409   // use pthread_join() later.  Makes threading more efficient.
5410   (void)pthread_detach(pthread_self());
5411   port_write(port);
5412 
5413   return(NULL);
5414 }
5415 
5416 
5417 
5418 
5419 
5420 //***********************************************************
5421 // Start port read & write threads
5422 // port is port# used
5423 //
5424 // open threads for reading and writing data to and from this
5425 // port.
5426 //***********************************************************
start_port_threads(int port)5427 int start_port_threads(int port)
5428 {
5429   int ok;
5430 
5431   port_id[port] = port;
5432   if (debug_level & 2)
5433   {
5434     fprintf(stderr,"Start port %d threads\n",port);
5435   }
5436 
5437   ok = 1;
5438   if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP)
5439   {
5440     if (debug_level & 2)
5441     {
5442       fprintf(stderr,"*** Startup of read/write threads for port %d ***\n",port);
5443     }
5444 
5445     /* start the two threads */
5446     if (pthread_create(&port_data[port].read_thread, NULL, read_access_port_thread, &port_id[port]))
5447     {
5448       /* error starting read thread*/
5449       fprintf(stderr,"Error starting read thread, port %d\n",port);
5450       port_data[port].read_thread = 0;
5451       ok = -1;
5452     }
5453     else if (pthread_create(&port_data[port].write_thread, NULL, write_access_port_thread, &port_id[port]))
5454     {
5455       /* error starting write thread*/
5456       fprintf(stderr,"Error starting write thread, port %d\n",port);
5457       port_data[port].write_thread = 0;
5458       ok = -1;
5459     }
5460 
5461   }
5462   else if (debug_level & 2)
5463   {
5464     fprintf(stderr,"*** Skipping startup of read/write threads for port %d ***\n",port);
5465   }
5466 
5467   if (debug_level & 2)
5468   {
5469     fprintf(stderr,"End port %d threads\n",port);
5470   }
5471 
5472   return(ok);
5473 }
5474 
5475 
5476 
5477 
5478 
5479 //***********************************************************
5480 // Clear Port Data
5481 // int port to be cleared
5482 //***********************************************************
clear_port_data(int port,int clear_more)5483 void clear_port_data(int port, int clear_more)
5484 {
5485 
5486   if (begin_critical_section(&port_data_lock, "interface.c:clear_port_data(1)" ) > 0)
5487   {
5488     fprintf(stderr,"port_data_lock, Port = %d\n", port);
5489   }
5490 
5491   port_data[port].device_type = -1;
5492   port_data[port].active = DEVICE_NOT_IN_USE;
5493   port_data[port].status = DEVICE_DOWN;
5494 
5495   // Show the latest status in the interface control dialog
5496   update_interface_list();
5497 
5498   port_data[port].device_name[0] = '\0';
5499   port_data[port].device_host_name[0] = '\0';
5500   port_data[port].addr_list = NULL;
5501 
5502   if (begin_critical_section(&connect_lock, "interface.c:clear_port_data(2)" ) > 0)
5503   {
5504     fprintf(stderr,"connect_lock, Port = %d\n", port);
5505   }
5506 
5507   port_data[port].thread_status = -1;
5508   port_data[port].connect_status = -1;
5509   port_data[port].read_thread = 0;
5510   port_data[port].write_thread = 0;
5511 
5512   if (end_critical_section(&connect_lock, "interface.c:clear_port_data(3)" ) > 0)
5513   {
5514     fprintf(stderr,"connect_lock, Port = %d\n", port);
5515   }
5516 
5517   port_data[port].decode_errors = 0;
5518   port_data[port].data_type = 0;
5519   port_data[port].socket_port = -1;
5520   port_data[port].device_host_pswd[0] = '\0';
5521 
5522   if (clear_more)
5523   {
5524     port_data[port].channel = -1;
5525   }
5526 
5527   port_data[port].channel2 = -1;
5528   port_data[port].ui_call[0] = '\0';
5529   port_data[port].dtr = 0;
5530   port_data[port].sp = -1;
5531   port_data[port].style = -1;
5532   port_data[port].errors = 0;
5533   port_data[port].bytes_input = 0l;
5534   port_data[port].bytes_output = 0l;
5535   port_data[port].bytes_input_last = 0l;
5536   port_data[port].bytes_output_last = 0l;
5537   port_data[port].port_activity = 1;    // First time-period is a freebie
5538   port_data[port].read_in_pos = 0;
5539   port_data[port].read_out_pos = 0;
5540   port_data[port].write_in_pos = 0;
5541   port_data[port].write_out_pos = 0;
5542 
5543   if (end_critical_section(&port_data_lock, "interface.c:clear_port_data(4)" ) > 0)
5544   {
5545     fprintf(stderr,"port_data_lock, Port = %d\n", port);
5546   }
5547 }
5548 
5549 
5550 
5551 
5552 
5553 //***********************************************************
5554 // Clear All Port Data
5555 //***********************************************************
clear_all_port_data(void)5556 void clear_all_port_data(void)
5557 {
5558   int i;
5559 
5560   for (i = 0; i < MAX_IFACE_DEVICES; i++)
5561   {
5562     clear_port_data(i,1);
5563   }
5564 }
5565 
5566 
5567 
5568 
5569 
5570 //***********************************************************
5571 // INIT Device names Data
5572 //***********************************************************
init_device_names(void)5573 void init_device_names(void)
5574 {
5575   xastir_snprintf(dtype[DEVICE_NONE].device_name,
5576                   sizeof(dtype[DEVICE_NONE].device_name),
5577                   "%s",
5578                   langcode("IFDNL00000"));
5579   xastir_snprintf(dtype[DEVICE_SERIAL_TNC].device_name,
5580                   sizeof(dtype[DEVICE_SERIAL_TNC].device_name),
5581                   "%s",
5582                   langcode("IFDNL00001"));
5583   xastir_snprintf(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name,
5584                   sizeof(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name),
5585                   "%s",
5586                   langcode("IFDNL00002"));
5587   xastir_snprintf(dtype[DEVICE_SERIAL_GPS].device_name,
5588                   sizeof(dtype[DEVICE_SERIAL_GPS].device_name),
5589                   "%s",
5590                   langcode("IFDNL00003"));
5591   xastir_snprintf(dtype[DEVICE_SERIAL_WX].device_name,
5592                   sizeof(dtype[DEVICE_SERIAL_WX].device_name),
5593                   "%s",
5594                   langcode("IFDNL00004"));
5595   xastir_snprintf(dtype[DEVICE_NET_STREAM].device_name,
5596                   sizeof(dtype[DEVICE_NET_STREAM].device_name),
5597                   "%s",
5598                   langcode("IFDNL00005"));
5599   xastir_snprintf(dtype[DEVICE_AX25_TNC].device_name,
5600                   sizeof(dtype[DEVICE_AX25_TNC].device_name),
5601                   "%s",
5602                   langcode("IFDNL00006"));
5603   xastir_snprintf(dtype[DEVICE_NET_GPSD].device_name,
5604                   sizeof(dtype[DEVICE_NET_GPSD].device_name),
5605                   "%s",
5606                   langcode("IFDNL00007"));
5607   xastir_snprintf(dtype[DEVICE_NET_WX].device_name,
5608                   sizeof(dtype[DEVICE_NET_WX].device_name),
5609                   "%s",
5610                   langcode("IFDNL00008"));
5611   xastir_snprintf(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name,
5612                   sizeof(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name),
5613                   "%s",
5614                   langcode("IFDNL00009"));
5615   xastir_snprintf(dtype[DEVICE_SERIAL_KISS_TNC].device_name,
5616                   sizeof(dtype[DEVICE_SERIAL_KISS_TNC].device_name),
5617                   "%s",
5618                   langcode("IFDNL00010"));
5619   xastir_snprintf(dtype[DEVICE_NET_DATABASE].device_name,
5620                   sizeof(dtype[DEVICE_NET_DATABASE].device_name),
5621                   "%s",
5622                   langcode("IFDNL00011"));
5623   xastir_snprintf(dtype[DEVICE_NET_AGWPE].device_name,
5624                   sizeof(dtype[DEVICE_NET_AGWPE].device_name),
5625                   "%s",
5626                   langcode("IFDNL00012"));
5627   xastir_snprintf(dtype[DEVICE_SERIAL_MKISS_TNC].device_name,
5628                   sizeof(dtype[DEVICE_SERIAL_MKISS_TNC].device_name),
5629                   "%s",
5630                   langcode("IFDNL00013"));
5631 
5632 #ifdef HAVE_DB
5633   // SQL Database (experimental)
5634   xastir_snprintf(dtype[DEVICE_SQL_DATABASE].device_name,
5635                   sizeof(dtype[DEVICE_SQL_DATABASE].device_name),
5636                   "%s",
5637                   langcode("IFDNL00014"));
5638 #endif /* HAVE_DB */
5639 
5640 }
5641 
5642 
5643 
5644 
5645 
5646 //***********************************************************
5647 // Delete Device.  Shuts down active port/ports.
5648 //***********************************************************
del_device(int port)5649 int del_device(int port)
5650 {
5651   int ok;
5652   char temp[300];
5653   long wait_time = 0;
5654 
5655 
5656   if (debug_level & 2)
5657   {
5658     fprintf(stderr,"Delete Device start\n");
5659   }
5660 
5661   ok = -1;
5662   switch (port_data[port].device_type)
5663   {
5664 
5665     case(DEVICE_SERIAL_TNC):
5666     case(DEVICE_SERIAL_KISS_TNC):
5667     case(DEVICE_SERIAL_MKISS_TNC):
5668     case(DEVICE_SERIAL_GPS):
5669     case(DEVICE_SERIAL_WX):
5670     case(DEVICE_SERIAL_TNC_HSP_GPS):
5671     case(DEVICE_SERIAL_TNC_AUX_GPS):
5672 
5673       switch (port_data[port].device_type)
5674       {
5675 
5676         case DEVICE_SERIAL_TNC:
5677 
5678           if (debug_level & 2)
5679           {
5680             fprintf(stderr,"Close a Serial TNC device\n");
5681           }
5682 
5683           begin_critical_section(&devices_lock, "interface.c:del_device" );
5684 
5685           xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file);
5686 
5687           end_critical_section(&devices_lock, "interface.c:del_device" );
5688 
5689           (void)command_file_to_tnc_port(port,get_data_base_dir(temp));
5690           break;
5691 
5692         case DEVICE_SERIAL_KISS_TNC:
5693           if (debug_level & 2)
5694           {
5695             fprintf(stderr,"Close a Serial KISS TNC device\n");
5696           }
5697           break;
5698 
5699         case DEVICE_SERIAL_MKISS_TNC:
5700           if (debug_level & 2)
5701           {
5702             fprintf(stderr,"Close a Serial MKISS TNC device\n");
5703           }
5704           break;
5705 
5706         case DEVICE_SERIAL_GPS:
5707           if (debug_level & 2)
5708           {
5709             fprintf(stderr,"Close a Serial GPS device\n");
5710           }
5711           if (using_gps_position)
5712           {
5713             using_gps_position--;
5714           }
5715           break;
5716 
5717         case DEVICE_SERIAL_WX:
5718           if (debug_level & 2)
5719           {
5720             fprintf(stderr,"Close a Serial WX device\n");
5721           }
5722 
5723           break;
5724 
5725         case DEVICE_SERIAL_TNC_HSP_GPS:
5726           if (debug_level & 2)
5727           {
5728             fprintf(stderr,"Close a Serial TNC w/HSP GPS\n");
5729           }
5730           if (using_gps_position)
5731           {
5732             using_gps_position--;
5733           }
5734 
5735           begin_critical_section(&devices_lock, "interface.c:del_device" );
5736 
5737           xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file);
5738 
5739           end_critical_section(&devices_lock, "interface.c:del_device" );
5740 
5741           (void)command_file_to_tnc_port(port,get_data_base_dir(temp));
5742           break;
5743 
5744         case DEVICE_SERIAL_TNC_AUX_GPS:
5745           if (debug_level & 2)
5746           {
5747             fprintf(stderr,"Close a Serial TNC w/AUX GPS\n");
5748           }
5749           if (using_gps_position)
5750           {
5751             using_gps_position--;
5752           }
5753 
5754           begin_critical_section(&devices_lock, "interface.c:del_device");
5755 
5756           sprintf(temp, "config/%s", devices[port].tnc_down_file);
5757 
5758           end_critical_section(&devices_lock, "interface.c:del_device");
5759 
5760           (void)command_file_to_tnc_port(port,
5761                                          get_data_base_dir(temp));
5762           break;
5763 
5764         default:
5765           break;
5766       }   // End of switch
5767 
5768 
5769       // Let the write queue empty before we return, to make
5770       // sure all of the data gets written out.
5771       while ( (port_data[port].write_in_pos != port_data[port].write_out_pos)
5772               && port_data[port].status == DEVICE_UP)
5773       {
5774 
5775         // Check whether we're hung waiting on the device
5776         if (wait_time > SERIAL_MAX_WAIT)
5777         {
5778           break;  // Break out of the while loop
5779         }
5780 
5781         sched_yield();
5782         usleep(25000);    // 25ms
5783         wait_time = wait_time + 25000;
5784       }
5785 
5786 
5787       if (debug_level & 2)
5788       {
5789         fprintf(stderr,"Serial detach\n");
5790       }
5791 
5792       ok = serial_detach(port);
5793       break;
5794 
5795     case(DEVICE_NET_STREAM):
5796     case(DEVICE_AX25_TNC):
5797     case(DEVICE_NET_GPSD):
5798     case(DEVICE_NET_WX):
5799     case(DEVICE_NET_DATABASE):
5800     case(DEVICE_NET_AGWPE):
5801 
5802       switch (port_data[port].device_type)
5803       {
5804 
5805         case DEVICE_NET_STREAM:
5806           if (debug_level & 2)
5807           {
5808             fprintf(stderr,"Close a Network stream\n");
5809           }
5810           break;
5811 
5812         case DEVICE_AX25_TNC:
5813           if (debug_level & 2)
5814           {
5815             fprintf(stderr,"Close a AX25 TNC device\n");
5816           }
5817           break;
5818 
5819         case DEVICE_NET_GPSD:
5820           if (debug_level & 2)
5821           {
5822             fprintf(stderr,"Close a Network GPSd stream\n");
5823           }
5824           if (using_gps_position)
5825           {
5826             using_gps_position--;
5827           }
5828           break;
5829 
5830         case DEVICE_NET_WX:
5831           if (debug_level & 2)
5832           {
5833             fprintf(stderr,"Close a Network WX stream\n");
5834           }
5835           break;
5836 
5837         case DEVICE_NET_DATABASE:
5838           if (debug_level & 2)
5839           {
5840             fprintf(stderr,"Close a Network Database stream\n");
5841           }
5842           break;
5843 
5844         case DEVICE_NET_AGWPE:
5845           if (debug_level & 2)
5846           {
5847             fprintf(stderr,"Close a Network AGWPE stream\n");
5848           }
5849           break;
5850 
5851         default:
5852           break;
5853       }
5854       if (debug_level & 2)
5855       {
5856         fprintf(stderr,"Net detach\n");
5857       }
5858 
5859       ok = net_detach(port);
5860       break;
5861 
5862 #ifdef HAVE_DB
5863     case DEVICE_SQL_DATABASE:
5864       if (debug_level & 2)
5865       {
5866         fprintf(stderr,"Close connection to database on device %d\n",port);
5867       }
5868       if (port_data[port].status==DEVICE_UP)
5869       {
5870         ok = closeConnection(&connections[port],port);
5871       }
5872       // remove the connection from the list of open connections
5873       /* clear port active */
5874       port_data[port].active = DEVICE_NOT_IN_USE;
5875       /* clear port status */
5876       port_data[port].active = DEVICE_DOWN;
5877       update_interface_list();
5878       fprintf(stderr,"Closed connection to database on device %d\n",port);
5879       break;
5880 #endif /* HAVE_DB */
5881 
5882     default:
5883       break;
5884   }
5885 
5886   if (ok)
5887   {
5888     int retvalue;
5889 
5890     if (debug_level & 2)
5891     {
5892       fprintf(stderr,"port detach OK\n");
5893     }
5894 
5895     usleep(100000);    // 100ms
5896     if (debug_level & 2)
5897     {
5898       fprintf(stderr,"Cancel threads\n");
5899     }
5900 
5901     if (begin_critical_section(&port_data_lock, "interface.c:del_device(1)" ) > 0)
5902     {
5903       fprintf(stderr,"port_data_lock, Port = %d\n", port);
5904     }
5905 
5906     if (begin_critical_section(&connect_lock, "interface.c:del_device(2)" ) > 0)
5907     {
5908       fprintf(stderr,"connect_lock, Port = %d\n", port);
5909     }
5910 
5911     if (port_data[port].read_thread != 0)   // If we have a thread defined
5912     {
5913       retvalue = pthread_cancel(port_data[port].read_thread);
5914       if (retvalue == ESRCH)
5915       {
5916       }
5917     }
5918 
5919     if (port_data[port].write_thread != 0)      // If we have a thread defined
5920     {
5921       retvalue = pthread_cancel(port_data[port].write_thread);
5922       // we used to test retvalue against ESRCH and throw a
5923       // warning if this failed, but it got commented out a very
5924       // long time ago (around 2003).
5925     }
5926 
5927     if (end_critical_section(&connect_lock, "interface.c:del_device(3)" ) > 0)
5928     {
5929       fprintf(stderr,"connect_lock, Port = %d\n", port);
5930     }
5931 
5932     if (end_critical_section(&port_data_lock, "interface.c:del_device(4)" ) > 0)
5933     {
5934       fprintf(stderr,"port_data_lock, Port = %d\n", port);
5935     }
5936 
5937     usleep(100000); // 100ms
5938   }
5939   else
5940   {
5941     if (debug_level & 2)
5942     {
5943       fprintf(stderr,"Port %d could not be closed\n",port);
5944     }
5945   }
5946   usleep(10);
5947 
5948   // Cover the case where someone plays with a GPS interface or
5949   // three and then turns it/them off again: They won't send a
5950   // posit again until the next restart or whenever they enable a
5951   // GPS interface again that has good data, unless we set this
5952   // variable again for them.
5953   if (!using_gps_position)
5954   {
5955     my_position_valid = 1;
5956   }
5957 
5958   return(ok);
5959 }
5960 
5961 
5962 #ifdef HAVE_DB
5963 /* Add a device, passing it a pointer to the ioparam
5964  * that describes the interface to start up, rather than passing
5965  * an extracted list of elements
5966  *
5967  * temporary addition for testing sql_database_functionality
5968  * when working, needs to be integrated into add_device
5969  */
add_device_by_ioparam(int port_avail,ioparam * device)5970 int add_device_by_ioparam(int port_avail, ioparam *device)
5971 {
5972   int ok;
5973   int got_conn;
5974   int done = 0;
5975   DataRow *dr;
5976   ok = -1;
5977 
5978   if (port_avail >= 0)
5979   {
5980 
5981     switch (device->device_type)
5982     {
5983       case DEVICE_SQL_DATABASE:
5984         if (debug_level & 4096)
5985         {
5986           fprintf(stderr,"Opening a sql db connection to %s\n",device->device_host_name);
5987         }
5988         clear_port_data(port_avail,0);
5989 
5990         port_data[port_avail].device_type = DEVICE_SQL_DATABASE;
5991         xastir_snprintf(port_data[port_avail].device_host_name,
5992                         sizeof(port_data[port_avail].device_host_name),
5993                         "%s",
5994                         device->device_host_name);
5995         if (connections_initialized==0)
5996         {
5997           if (debug_level & 4096)
5998           {
5999             fprintf(stderr,"Calling initConnections in add_device_by_ioparam\n");
6000           }
6001           fprintf(stderr,"adddevice, initializing connections");
6002           connections_initialized = initConnections();
6003         }
6004         if (debug_level & 4096)
6005         {
6006           fprintf(stderr,"Opening (in interfaces) device on port [%d] with connection [%p]\n",port_avail,&connections[port_avail]);
6007           fprintf(stderr,"device [%p][%p] device_type=%d\n",device,&device,device->device_type);
6008         }
6009         got_conn = 0;
6010         got_conn=openConnection(device, &connections[port_avail]);
6011         if (debug_level & 4096)
6012         {
6013           fprintf(stderr,"got_conn connections[%d] [%p] result=%d\n",port_avail,&connections[port_avail],got_conn);
6014           if (got_conn==1)
6015           {
6016             fprintf(stderr,"got_conn connection type %d\n",connections[port_avail].type);
6017           }
6018         }
6019         if ((got_conn == 1) && (!(connections[port_avail].type==NULL)))
6020         {
6021           if (debug_level & 4096)
6022           {
6023             fprintf(stderr, "Opened connection [%d] type=[%d]\n",port_avail,connections[port_avail].type);
6024           }
6025           ok = 1;
6026           port_data[port_avail].active = DEVICE_IN_USE;
6027           port_data[port_avail].status = DEVICE_UP;
6028         }
6029         else
6030         {
6031           port_data[port_avail].active = DEVICE_IN_USE;
6032           port_data[port_avail].status = DEVICE_ERROR;
6033         }
6034         // Show the latest status in the interface control dialog
6035         update_interface_list();
6036         if (ok == 1)
6037         {
6038           /* if connected save top of call list */
6039           ok = storeStationSimpleToGisDb(&connections[port_avail], n_first);
6040           if (ok==1)
6041           {
6042             if (debug_level & 4096)
6043             {
6044               fprintf(stderr,"Stored station n_first\n");
6045             }
6046             // iterate through station_pointers and write all stations currently known
6047             dr = n_first->n_next;
6048             if (dr!=NULL)
6049             {
6050               while (done==0)
6051               {
6052                 if (debug_level & 4096)
6053                 {
6054                   fprintf(stderr,"storing additional stations\n");
6055                 }
6056                 // Need to check that stations aren't from the database
6057                 // preventing creation of duplicate round trip records.
6058                 ok = storeStationSimpleToGisDb(&connections[port_avail], dr);
6059                 if (ok==1)
6060                 {
6061                   dr = dr->n_next;
6062                   if (dr==NULL)
6063                   {
6064                     done = 1;
6065                   }
6066                 }
6067                 else
6068                 {
6069                   done = 1;
6070                 }
6071               }
6072             }
6073           }
6074         }
6075     }
6076   }
6077   return ok;
6078 }
6079 #endif /* HAVE_DB */
6080 
6081 
6082 //***********************************************************
6083 // Add Device.  Starts up ports (makes them active).
6084 // dev_type is the device type to add
6085 // dev_num is the device name
6086 // dev_hst is the host name to connect to (network only)
6087 // dev_sck_p is the socket port to connect to (network only)
6088 // dev_sp is the baud rate of the port (serial only)
6089 // dev_sty is the port style (serial only)
6090 //
6091 // this will return the port # if one is available
6092 // otherwise it will return -1 if there is an error
6093 //***********************************************************
add_device(int port_avail,int dev_type,char * dev_nm,char * passwd,int dev_sck_p,int dev_sp,int dev_sty,int reconnect,char * filter_string)6094 int add_device(int port_avail,int dev_type,char *dev_nm,char *passwd,int dev_sck_p,
6095                int dev_sp,int dev_sty,int reconnect, char *filter_string)
6096 {
6097   char logon_txt[600];
6098   char init_kiss_string[5];   // KISS-mode on startup
6099   int ok;
6100   char temp[300];
6101   char verstr[15];
6102 
6103   if ( (dev_nm == NULL) || (passwd == NULL) )
6104   {
6105     return(-1);
6106   }
6107 
6108   if (dev_nm[0] == '\0')
6109   {
6110     return(-1);
6111   }
6112 
6113   xastir_snprintf(verstr,
6114                   sizeof(verstr),
6115                   "XASTIR %s",
6116                   VERSION);
6117 
6118   ok = -1;
6119   if (port_avail >= 0)
6120   {
6121     if (debug_level & 2)
6122     {
6123       fprintf(stderr,"Port Available %d\n",port_avail);
6124     }
6125 
6126     switch(dev_type)
6127     {
6128 
6129       case DEVICE_SERIAL_TNC:
6130       case DEVICE_SERIAL_KISS_TNC:
6131       case DEVICE_SERIAL_MKISS_TNC:
6132       case DEVICE_SERIAL_GPS:
6133       case DEVICE_SERIAL_WX:
6134       case DEVICE_SERIAL_TNC_HSP_GPS:
6135       case DEVICE_SERIAL_TNC_AUX_GPS:
6136 
6137         switch (dev_type)
6138         {
6139 
6140           case DEVICE_SERIAL_TNC:
6141             if (debug_level & 2)
6142             {
6143               fprintf(stderr,"Opening a Serial TNC device\n");
6144             }
6145 
6146             break;
6147 
6148           case DEVICE_SERIAL_KISS_TNC:
6149             if (debug_level & 2)
6150             {
6151               fprintf(stderr,"Opening a Serial KISS TNC device\n");
6152             }
6153 
6154             break;
6155 
6156           case DEVICE_SERIAL_MKISS_TNC:
6157             if (debug_level & 2)
6158             {
6159               fprintf(stderr,"Opening a Serial MKISS TNC device\n");
6160             }
6161 
6162             break;
6163 
6164           case DEVICE_SERIAL_GPS:
6165             if (debug_level & 2)
6166             {
6167               fprintf(stderr,"Opening a Serial GPS device\n");
6168             }
6169             // Must wait for valid GPS parsing after
6170             // sending one posit.
6171             my_position_valid = 1;
6172             using_gps_position++;
6173             statusline(langcode("BBARSTA041"),1);
6174             break;
6175 
6176           case DEVICE_SERIAL_WX:
6177             if (debug_level & 2)
6178             {
6179               fprintf(stderr,"Opening a Serial WX device\n");
6180             }
6181 
6182             break;
6183 
6184           case DEVICE_SERIAL_TNC_HSP_GPS:
6185             if (debug_level & 2)
6186             {
6187               fprintf(stderr,"Opening a Serial TNC w/HSP GPS device\n");
6188             }
6189             // Must wait for valid GPS parsing after
6190             // sending one posit.
6191             my_position_valid = 1;
6192             using_gps_position++;
6193             statusline(langcode("BBARSTA041"),1);
6194             break;
6195 
6196           case DEVICE_SERIAL_TNC_AUX_GPS:
6197             if (debug_level & 2)
6198             {
6199               fprintf(stderr,"Opening a Serial TNC w/AUX GPS device\n");
6200             }
6201             // Must wait for valid GPS parsing after
6202             // sending one posit.
6203             my_position_valid = 1;
6204             using_gps_position++;
6205             statusline(langcode("BBARSTA041"),1);
6206             break;
6207 
6208           default:
6209             break;
6210         }
6211         clear_port_data(port_avail,0);
6212 
6213         port_data[port_avail].device_type = dev_type;
6214         xastir_snprintf(port_data[port_avail].device_name,
6215                         sizeof(port_data[port_avail].device_name),
6216                         "%s",
6217                         dev_nm);
6218         port_data[port_avail].sp = dev_sp;
6219         port_data[port_avail].style = dev_sty;
6220         if (dev_type == DEVICE_SERIAL_WX)
6221         {
6222           if (strcmp("1",passwd) == 0)
6223           {
6224             port_data[port_avail].data_type = 1;
6225           }
6226         }
6227 
6228         ok = serial_init(port_avail);
6229         break;
6230 
6231       case DEVICE_NET_STREAM:
6232         if (debug_level & 2)
6233         {
6234           fprintf(stderr,"Opening a Network stream\n");
6235         }
6236 
6237         clear_port_data(port_avail,0);
6238 
6239         port_data[port_avail].device_type = DEVICE_NET_STREAM;
6240         xastir_snprintf(port_data[port_avail].device_host_name,
6241                         sizeof(port_data[port_avail].device_host_name),
6242                         "%s",
6243                         dev_nm);
6244         xastir_snprintf(port_data[port_avail].device_host_pswd,
6245                         sizeof(port_data[port_avail].device_host_pswd),
6246                         "%s",
6247                         passwd);
6248         port_data[port_avail].socket_port = dev_sck_p;
6249         port_data[port_avail].reconnect = reconnect;
6250 
6251         ok = net_init(port_avail);
6252 
6253         if (ok == 1)
6254         {
6255 
6256           /* if connected now send password */
6257           if (strlen(passwd))
6258           {
6259 
6260             if (filter_string != NULL
6261                 && strlen(filter_string) > 0)      // Filter specified
6262             {
6263 
6264               // Please note that "filter" must be the 8th
6265               // parameter on the line in order to be
6266               // parsed properly by the servers.
6267               xastir_snprintf(logon_txt,
6268                               sizeof(logon_txt),
6269                               "user %s pass %s vers %s filter %s%c%c",
6270                               my_callsign,
6271                               passwd,
6272                               verstr,
6273                               filter_string,
6274                               '\r',
6275                               '\n');
6276             }
6277             else    // No filter specified
6278             {
6279               xastir_snprintf(logon_txt,
6280                               sizeof(logon_txt),
6281                               "user %s pass %s vers %s%c%c",
6282                               my_callsign,
6283                               passwd,
6284                               verstr,
6285                               '\r',
6286                               '\n');
6287             }
6288           }
6289           else
6290           {
6291             xastir_snprintf(logon_txt,
6292                             sizeof(logon_txt),
6293                             "user %s pass -1 vers %s %c%c",
6294                             my_callsign,
6295                             verstr,
6296                             '\r',
6297                             '\n');
6298           }
6299           port_write_string(port_avail,logon_txt);
6300         }
6301         break;
6302 
6303       case DEVICE_AX25_TNC:
6304         if (debug_level & 2)
6305         {
6306           fprintf(stderr,"Opening a network AX25 TNC\n");
6307         }
6308 
6309         clear_port_data(port_avail,0);
6310 
6311         port_data[port_avail].device_type = DEVICE_AX25_TNC;
6312         xastir_snprintf(port_data[port_avail].device_name,
6313                         sizeof(port_data[port_avail].device_name),
6314                         "%s",
6315                         dev_nm);
6316 
6317         ok = ax25_init(port_avail);
6318         break;
6319 
6320       case DEVICE_NET_GPSD:
6321         if (debug_level & 2)
6322         {
6323           fprintf(stderr,"Opening a network GPS using gpsd\n");
6324         }
6325 
6326         clear_port_data(port_avail,0);
6327 
6328         port_data[port_avail].device_type = DEVICE_NET_GPSD;
6329         xastir_snprintf(port_data[port_avail].device_host_name,
6330                         sizeof(port_data[port_avail].device_host_name),
6331                         "%s",
6332                         dev_nm);
6333         port_data[port_avail].socket_port = dev_sck_p;
6334         port_data[port_avail].reconnect = reconnect;
6335 
6336         ok = net_init(port_avail);
6337         if (ok == 1)
6338         {
6339 
6340           // Pre-2.90 GPSD protocol
6341           xastir_snprintf(logon_txt, sizeof(logon_txt), "R\r\n");
6342           port_write_string(port_avail,logon_txt);
6343 
6344           // Post-2.90 GPSD protocol is handled near the
6345           // bottom of this routine.
6346 
6347           // Must wait for valid GPS parsing after sending
6348           // one posit.
6349           my_position_valid = 1;
6350           using_gps_position++;
6351           statusline(langcode("BBARSTA041"),1);
6352         }
6353         break;
6354 
6355       case DEVICE_NET_WX:
6356         if (debug_level & 2)
6357         {
6358           fprintf(stderr,"Opening a network WX\n");
6359         }
6360 
6361         clear_port_data(port_avail,0);
6362 
6363         port_data[port_avail].device_type = DEVICE_NET_WX;
6364         xastir_snprintf(port_data[port_avail].device_host_name,
6365                         sizeof(port_data[port_avail].device_host_name),
6366                         "%s",
6367                         dev_nm);
6368         port_data[port_avail].socket_port = dev_sck_p;
6369         port_data[port_avail].reconnect = reconnect;
6370         if (strcmp("1",passwd) == 0)
6371         {
6372           port_data[port_avail].data_type = 1;
6373         }
6374 
6375         ok = net_init(port_avail);
6376         if (ok == 1)
6377         {
6378           /* if connected now send call and program version */
6379           xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n');
6380           port_write_string(port_avail,logon_txt);
6381         }
6382         break;
6383 
6384       case DEVICE_NET_DATABASE:
6385         if (debug_level & 2)
6386         {
6387           fprintf(stderr,"Opening a network database stream\n");
6388         }
6389 
6390         clear_port_data(port_avail,0);
6391 
6392         port_data[port_avail].device_type = DEVICE_NET_DATABASE;
6393         xastir_snprintf(port_data[port_avail].device_host_name,
6394                         sizeof(port_data[port_avail].device_host_name),
6395                         "%s",
6396                         dev_nm);
6397         port_data[port_avail].socket_port = dev_sck_p;
6398         port_data[port_avail].reconnect = reconnect;
6399         if (strcmp("1",passwd) == 0)
6400         {
6401           port_data[port_avail].data_type = 1;
6402         }
6403 
6404         ok = net_init(port_avail);
6405         if (ok == 1)
6406         {
6407           /* if connected now send call and program version */
6408           xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n');
6409           port_write_string(port_avail,logon_txt);
6410         }
6411         break;
6412 
6413       case DEVICE_NET_AGWPE:
6414         if (debug_level & 2)
6415         {
6416           fprintf(stderr,"Opening a network AGWPE stream");
6417         }
6418 
6419         clear_port_data(port_avail,0);
6420 
6421         port_data[port_avail].device_type = DEVICE_NET_AGWPE;
6422         xastir_snprintf(port_data[port_avail].device_host_name,
6423                         sizeof(port_data[port_avail].device_host_name),
6424                         "%s",
6425                         dev_nm);
6426         port_data[port_avail].socket_port = dev_sck_p;
6427         port_data[port_avail].reconnect = reconnect;
6428         if (strcmp("1",passwd) == 0)
6429         {
6430           port_data[port_avail].data_type = 1;
6431         }
6432 
6433         ok = net_init(port_avail);
6434 
6435         if (ok == 1)
6436         {
6437 
6438           // If password isn't empty, send login
6439           // information
6440           //
6441           if (strlen(passwd) != 0)
6442           {
6443 
6444             // Send the login packet
6445             send_agwpe_packet(port_avail,
6446                               0,                       // AGWPE RadioPort
6447                               'P',                     // Login/Password Frame
6448                               NULL,                    // FromCall
6449                               NULL,                    // ToCall
6450                               NULL,                    // Path
6451                               (unsigned char *)passwd, // Data
6452                               strlen(passwd));         // Length
6453           }
6454         }
6455         break;
6456 
6457       default:
6458         break;
6459     }
6460 
6461     if (ok == 1)    // If port is connected...
6462     {
6463 
6464       if (debug_level & 2)
6465       {
6466         fprintf(stderr,"*** add_device: ok: %d ***\n",ok);
6467       }
6468 
6469       /* if all is ok check and start read write threads */
6470       (void)start_port_threads(port_avail);
6471       usleep(100000); // 100ms
6472 
6473       switch (dev_type)
6474       {
6475 
6476         case DEVICE_SERIAL_TNC:
6477         case DEVICE_SERIAL_TNC_HSP_GPS:
6478         case DEVICE_SERIAL_TNC_AUX_GPS:
6479 
6480           if (ok == 1)
6481           {
6482             xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port_avail].tnc_up_file);
6483             (void)command_file_to_tnc_port(port_avail,get_data_base_dir(temp));
6484           }
6485           break;
6486 
6487         case DEVICE_SERIAL_KISS_TNC:
6488 
6489           // Initialize KISS-Mode at startup
6490           if (devices[port_avail].init_kiss)
6491           {
6492             xastir_snprintf(init_kiss_string,
6493                             sizeof(init_kiss_string),
6494                             "\x1B@k\r");    // [ESC@K sets tnc from terminal- into kissmode
6495             port_write_string(port_avail,init_kiss_string);
6496             usleep(100000); // wait a little bit...
6497           }
6498 
6499           // Send the KISS parameters to the TNC
6500           send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay));
6501           send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence));
6502           send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime));
6503           send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail));
6504           send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex);
6505           break;
6506 
6507         //WE7U
6508         case DEVICE_SERIAL_MKISS_TNC:
6509           // Send the KISS parameters to the TNC.  We'll
6510           // need to send them to the correct port for
6511           // this MKISS device.
6512           send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay));
6513           send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence));
6514           send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime));
6515           send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail));
6516           send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex);
6517           break;
6518 
6519         case DEVICE_NET_AGWPE:
6520 
6521           // Query for the AGWPE version
6522           //
6523           send_agwpe_packet(port_avail,
6524                             0,      // AGWPE RadioPort
6525                             'R',    // Request SW Version Frame
6526                             NULL,   // FromCall
6527                             NULL,   // ToCall
6528                             NULL,   // Path
6529                             NULL,   // Data
6530                             0);     // Length
6531 
6532 
6533           // Query for port information
6534           //
6535           send_agwpe_packet(port_avail,
6536                             0,      // AGWPE RadioPort
6537                             'G',    // Request Port Info Frame
6538                             NULL,   // FromCall
6539                             NULL,   // ToCall
6540                             NULL,   // Path
6541                             NULL,   // Data
6542                             0);     // Length
6543 
6544           // Ask to receive "raw" frames
6545           //
6546           send_agwpe_packet(port_avail,
6547                             0,      // AGWPE RadioPort
6548                             'k',    // Request Raw Packets Frame
6549                             NULL,   // FromCall
6550                             NULL,   // ToCall
6551                             NULL,   // Path
6552                             NULL,   // Data
6553                             0);     // Length
6554 
6555 
6556           /*
6557           // Send a dummy UI frame for testing purposes.
6558           //
6559           send_agwpe_packet(port_avail,
6560           atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port
6561           '\0',       // type
6562           "TEST-3",   // FromCall
6563           "APRS",     // ToCall
6564           NULL,       // Path
6565           "Test",     // Data
6566           4);         // length
6567 
6568 
6569           // Send another dummy UI frame.
6570           //
6571           send_agwpe_packet(port_avail,
6572           atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port
6573           '\0',       // type
6574           "TEST-3",   // FromCall
6575           "APRS",     // ToCall
6576           "RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1", // Path
6577           "Testing this darned thing!",   // Data
6578           26);     // length
6579           */
6580 
6581           break;
6582 
6583         case DEVICE_NET_GPSD:
6584 
6585           // Post-2.90 GPSD protocol
6586           // (Pre-2.90 protocol handled in a prior section of
6587           // this routine)
6588           xastir_snprintf(logon_txt, sizeof(logon_txt), "?WATCH={\"enable\":true,\"nmea\":true}\r\n");
6589           port_write_string(port_avail,logon_txt);
6590           break;
6591 
6592         default:
6593           break;
6594       }
6595     }
6596 
6597     if (ok == -1)
6598     {
6599       xastir_snprintf(temp, sizeof(temp), langcode("POPEM00015"), port_avail);
6600       popup_message(langcode("POPEM00004"),temp);
6601       port_avail = -1;
6602     }
6603     else
6604     {
6605       if (ok == 0)
6606       {
6607         xastir_snprintf(temp, sizeof(temp), langcode("POPEM00016"), port_avail);
6608         popup_message(langcode("POPEM00004"),temp);
6609         port_avail = -1;
6610       }
6611     }
6612   }
6613   else
6614   {
6615     popup_message(langcode("POPEM00004"),langcode("POPEM00017"));
6616   }
6617 
6618   return(port_avail);
6619 }
6620 
6621 
6622 
6623 
6624 
6625 //***********************************************************
6626 // port status
6627 // port is the port to get status on
6628 //***********************************************************
port_stats(int port)6629 void port_stats(int port)
6630 {
6631   if (port >= 0)
6632   {
6633     fprintf(stderr,"Port %d %s Status\n\n",port,dtype[port_data[port].device_type].device_name);
6634     fprintf(stderr,"Errors %d\n",port_data[port].errors);
6635     fprintf(stderr,"Reconnects %d\n",port_data[port].reconnects);
6636     fprintf(stderr,"Bytes in: %ld  out: %ld\n",(long)port_data[port].bytes_input,(long)port_data[port].bytes_output);
6637     fprintf(stderr,"\n");
6638   }
6639 }
6640 
6641 
6642 
6643 
6644 
6645 //***********************************************************
6646 // startup defined ports
6647 //
6648 // port = -2: Start all defined interfaces
6649 // port = -1: Start all interfaces with "Activate on Startup"
6650 // port = 0 - MAX: Start only the one port specified
6651 //***********************************************************
startup_all_or_defined_port(int port)6652 void startup_all_or_defined_port(int port)
6653 {
6654   int i, override;
6655   int start;
6656 
6657   override = 0;
6658 
6659   switch (port)
6660   {
6661 
6662     case -1:    // Start if "Activate on Startup" enabled
6663       start = 0;
6664       break;
6665 
6666     case -2:    // Start all interfaces, period!
6667       start = 0;
6668       override = 1;
6669       break;
6670 
6671     default:    // Start only the interface specified in "port"
6672       start = port;
6673       override = 1;
6674       break;
6675   }
6676 
6677   begin_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" );
6678 
6679   for (i = start; i < MAX_IFACE_DEVICES; i++)
6680   {
6681 
6682     // Only start ports that aren't already up
6683     if ( (port_data[i].active != DEVICE_IN_USE)
6684          || (port_data[i].status != DEVICE_UP) )
6685     {
6686 
6687       switch (devices[i].device_type)
6688       {
6689 
6690         case DEVICE_NET_STREAM:
6691           if (devices[i].connect_on_startup == 1 || override)
6692           {
6693             (void)add_device(i,
6694                              DEVICE_NET_STREAM,
6695                              devices[i].device_host_name,
6696                              devices[i].device_host_pswd,
6697                              devices[i].sp,
6698                              0,
6699                              0,
6700                              devices[i].reconnect,
6701                              devices[i].device_host_filter_string);
6702           }
6703           break;
6704 
6705         case DEVICE_NET_DATABASE:
6706           if (devices[i].connect_on_startup == 1 || override)
6707           {
6708             (void)add_device(i,
6709                              DEVICE_NET_DATABASE,
6710                              devices[i].device_host_name,
6711                              devices[i].device_host_pswd,
6712                              devices[i].sp,
6713                              0,
6714                              0,
6715                              devices[i].reconnect,
6716                              devices[i].device_host_filter_string);
6717           }
6718           break;
6719 
6720         case DEVICE_NET_AGWPE:
6721           if (devices[i].connect_on_startup == 1 || override)
6722           {
6723             (void)add_device(i,
6724                              DEVICE_NET_AGWPE,
6725                              devices[i].device_host_name,
6726                              devices[i].device_host_pswd,
6727                              devices[i].sp,
6728                              0,
6729                              0,
6730                              devices[i].reconnect,
6731                              devices[i].device_host_filter_string);
6732           }
6733           break;
6734 
6735         case DEVICE_NET_GPSD:
6736           if (devices[i].connect_on_startup == 1 || override)
6737           {
6738             (void)add_device(i,
6739                              DEVICE_NET_GPSD,
6740                              devices[i].device_host_name,
6741                              "",
6742                              devices[i].sp,
6743                              0,
6744                              0,
6745                              devices[i].reconnect,
6746                              "");
6747           }
6748           break;
6749 
6750         case DEVICE_SERIAL_WX:
6751           if (devices[i].connect_on_startup == 1 || override)
6752           {
6753             (void)add_device(i,
6754                              DEVICE_SERIAL_WX,
6755                              devices[i].device_name,
6756                              devices[i].device_host_pswd,
6757                              -1,
6758                              devices[i].sp,
6759                              devices[i].style,
6760                              0,
6761                              "");
6762           }
6763           break;
6764 
6765         case DEVICE_NET_WX:
6766           if (devices[i].connect_on_startup == 1 || override)
6767           {
6768             (void)add_device(i,
6769                              DEVICE_NET_WX,
6770                              devices[i].device_host_name,
6771                              devices[i].device_host_pswd,
6772                              devices[i].sp,
6773                              0,
6774                              0,
6775                              devices[i].reconnect,
6776                              "");
6777           }
6778           break;
6779 
6780         case DEVICE_SERIAL_GPS:
6781           if (devices[i].connect_on_startup == 1 || override)
6782           {
6783             (void)add_device(i,
6784                              DEVICE_SERIAL_GPS,
6785                              devices[i].device_name,
6786                              "",
6787                              -1,
6788                              devices[i].sp,
6789                              devices[i].style,
6790                              0,
6791                              "");
6792           }
6793           break;
6794 
6795         case DEVICE_SERIAL_TNC:
6796         case DEVICE_SERIAL_KISS_TNC:
6797         case DEVICE_SERIAL_MKISS_TNC:
6798         case DEVICE_SERIAL_TNC_HSP_GPS:
6799         case DEVICE_SERIAL_TNC_AUX_GPS:
6800 
6801           if (devices[i].connect_on_startup == 1 || override)
6802           {
6803             (void)add_device(i,
6804                              devices[i].device_type,
6805                              devices[i].device_name,
6806                              "",
6807                              -1,
6808                              devices[i].sp,
6809                              devices[i].style,
6810                              0,
6811                              "");
6812           }
6813           break;
6814 
6815         case DEVICE_AX25_TNC:
6816           if (devices[i].connect_on_startup == 1 || override)
6817           {
6818             (void)add_device(i,
6819                              DEVICE_AX25_TNC,
6820                              devices[i].device_name,
6821                              "",
6822                              -1,
6823                              -1,
6824                              -1,
6825                              0,
6826                              "");
6827           }
6828           break;
6829 #ifdef HAVE_DB
6830         case DEVICE_SQL_DATABASE:
6831           if (debug_level & 4096)
6832           {
6833             fprintf(stderr,"Device %d Connect_on_startup=%d\n",i,devices[i].connect_on_startup);
6834           }
6835           if (devices[i].connect_on_startup == 1 || override)
6836           {
6837             ioparam *d = &devices[i];
6838             if (debug_level & 4096)
6839             {
6840               fprintf(stderr,"Opening a sql db with device type %d\n",d->device_type);
6841             }
6842             (void)add_device_by_ioparam(i, &devices[i]);
6843             if (debug_level & 4096)
6844             {
6845               fprintf(stderr, "added device by ioparam [%d] type=[%d]\n",i,connections[i].type);
6846             }
6847           }
6848           break;
6849 #endif /* HAVE_DB */
6850 
6851         default:
6852           break;
6853       }   // End of switch
6854     }
6855     else if (debug_level & 2)
6856     {
6857       fprintf(stderr,"Skipping port %d, it's already running\n",i);
6858     }
6859 
6860     if (port != -1 && port != -2)
6861     {
6862       // We're doing a specific port #, so stop the loop
6863       i = MAX_IFACE_DEVICES+1;
6864     }
6865   }
6866 
6867   end_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" );
6868 
6869 }
6870 
6871 
6872 
6873 
6874 
6875 //***********************************************************
6876 // shutdown active ports
6877 //
6878 // port = -1:  Shut down all active ports
6879 // port = 0 to max: Shut down the specified port if active
6880 //***********************************************************
shutdown_all_active_or_defined_port(int port)6881 void shutdown_all_active_or_defined_port(int port)
6882 {
6883   int i;
6884   int start;
6885 
6886   if (debug_level & 2)
6887   {
6888     fprintf(stderr,"\nshutdown_all_active_or_defined_port: %d\n\n",port);
6889   }
6890 
6891   if (port == -1)
6892   {
6893     start = 0;
6894   }
6895   else
6896   {
6897     start = port;
6898   }
6899 
6900   for( i = start; i < MAX_IFACE_DEVICES; i++ )
6901   {
6902     if ( (port_data[i].active == DEVICE_IN_USE)
6903          && ( (port_data[i].status == DEVICE_UP)
6904               || (port_data[i].status == DEVICE_ERROR) ) )
6905     {
6906       if (debug_level & 2)
6907       {
6908         fprintf(stderr,"Shutting down port %d \n",i);
6909       }
6910 
6911       (void)del_device(i);
6912     }
6913     if (port != -1) // Stop after one iteration if port specified
6914     {
6915       i = MAX_IFACE_DEVICES+1;
6916     }
6917   }
6918 }
6919 
6920 
6921 
6922 
6923 
6924 //*************************************************************
6925 // check ports
6926 //
6927 // Called periodically by main.c:UpdateTime() function.
6928 // Attempts to reconnect interfaces that are down.
6929 //*************************************************************
check_ports(void)6930 void check_ports(void)
6931 {
6932   int i;
6933   int temp;
6934 
6935   for (i = 0; i < MAX_IFACE_DEVICES; i++)
6936   {
6937 
6938     switch (port_data[i].device_type)
6939     {
6940       case(DEVICE_NET_STREAM):
6941       //case(DEVICE_AX25_TNC):
6942       case(DEVICE_NET_GPSD):
6943       case(DEVICE_NET_WX):
6944         if (port_data[i].port_activity == 0)
6945         {
6946           // We've seen no activity for one time period.  This variable
6947           // is updated in interface_gui.c
6948 
6949           if (port_data[i].status == DEVICE_ERROR)
6950           {
6951             // We're already in the error state, so force a reconnect
6952             port_data[i].reconnects = -1;
6953           }
6954           else if (port_data[i].status == DEVICE_UP)
6955           {
6956             // No activity on a port that's being used.
6957             // Cause a reconnect at the next iteration
6958             if (debug_level & 2)
6959             {
6960               fprintf(stderr,"check_ports(): Inactivity on port %d, DEVICE_ERROR ***\n",i);
6961             }
6962             port_data[i].status = DEVICE_ERROR; // No activity, so force a shutdown
6963 
6964             // Show the latest status in the interface control dialog
6965             update_interface_list();
6966 
6967 
6968             // If the below statement is enabled, it causes an immediate reconnect
6969             // after one time-period of inactivity, currently 7.5 minutes, as set in
6970             // main.c:UpdateTime().  This means the symbol will never change from green
6971             // to red on the status bar, so the operator might not know about a
6972             // connection that is being constantly reconnected.  By leaving it commented
6973             // out we get one time period of red, and then it will reconnect at the 2nd
6974             // time period.  This means we can reconnect within 15 minutes if a line
6975             // goes dead.
6976             //
6977             port_data[i].reconnects = -1;     // Causes an immediate reconnect
6978           }
6979 
6980         }
6981         else    // We saw activity on this port.
6982         {
6983           port_data[i].port_activity = 0;     // Reset counter for next time
6984         }
6985         break;
6986     }
6987 
6988     if (port_data[i].active == DEVICE_IN_USE && port_data[i].status == DEVICE_ERROR)
6989     {
6990       if (debug_level & 2)
6991       {
6992         fprintf(stderr,"Found device error on port %d\n",i);
6993       }
6994 
6995       if (port_data[i].reconnect == 1)
6996       {
6997         port_data[i].reconnects++;
6998         temp = port_data[i].reconnects;
6999         if (temp < 1)
7000         {
7001           if (debug_level & 2)
7002           {
7003             fprintf(stderr,"Device asks for reconnect count now at %d\n",temp);
7004           }
7005 
7006           if (debug_level & 2)
7007           {
7008             fprintf(stderr,"Shutdown device %d\n",i);
7009           }
7010 
7011           shutdown_all_active_or_defined_port(i);
7012 
7013           if (debug_level & 2)
7014           {
7015             fprintf(stderr,"Starting device %d\n",i);
7016           }
7017 
7018           startup_all_or_defined_port(i);
7019 
7020           /* if error on startup */
7021           if (port_data[i].status == DEVICE_ERROR)
7022           {
7023             port_data[i].reconnects = temp;
7024           }
7025         }
7026         else
7027         {
7028           if (debug_level & 2)
7029           {
7030             fprintf(stderr,"Device has either too many errors, or no activity at all!\n");
7031           }
7032 
7033           port_data[i].reconnects = temp - 2;
7034         }
7035       }
7036     }
7037   }
7038 }
7039 
7040 
7041 
7042 
7043 
7044 static char unproto_path_txt[MAX_LINE_SIZE+5];
7045 
7046 
7047 
7048 
7049 
7050 // Function which selects an unproto path in round-robin fashion.
7051 // Once we select a path, we save the number selected back to
7052 // devices[port].unprotonum so that the next time around we select
7053 // the next in the sequence.  If we don't come up with a valid
7054 // unproto path, we use the unproto path: "WIDE2-2".
7055 //
7056 // Input:  Port number
7057 // Ouput:  String pointer containing unproto path
7058 //
7059 // WE7U:  Should we check to make sure that there are printable
7060 // characters in the path?
7061 //
select_unproto_path(int port)7062 unsigned char *select_unproto_path(int port)
7063 {
7064   int count;
7065   int done;
7066   int temp;
7067   int bump_up;
7068 
7069 
7070   // Set unproto path:
7071   // We look for a non-null path entry starting at the current
7072   // value of "unprotonum".  The first non-null path wins.
7073   count = 0;
7074   done = 0;
7075   bump_up = 0;
7076 
7077 
7078   while (!done && (count < 3))
7079   {
7080     temp = (devices[port].unprotonum + count) % 3;
7081     switch (temp)
7082     {
7083 
7084       case 0:
7085         if (strlen(devices[port].unproto1) > 0)
7086         {
7087           xastir_snprintf(unproto_path_txt,
7088                           sizeof(unproto_path_txt),
7089                           "%s",
7090                           devices[port].unproto1);
7091           done++;
7092         }
7093         else
7094         {
7095           // No path entered here.  Skip this path in the
7096           // rotation for next time.
7097           bump_up++;
7098         }
7099         break;
7100 
7101       case 1:
7102         if (strlen(devices[port].unproto2) > 0)
7103         {
7104           xastir_snprintf(unproto_path_txt,
7105                           sizeof(unproto_path_txt),
7106                           "%s",
7107                           devices[port].unproto2);
7108           done++;
7109         }
7110         else
7111         {
7112           // No path entered here.  Skip this path in
7113           // the rotation for next time.
7114           bump_up++;
7115         }
7116         break;
7117 
7118       case 2:
7119         if (strlen(devices[port].unproto3) > 0)
7120         {
7121           xastir_snprintf(unproto_path_txt,
7122                           sizeof(unproto_path_txt),
7123                           "%s",
7124                           devices[port].unproto3);
7125           done++;
7126         }
7127         else
7128         {
7129           // No path entered here.  Skip this path in
7130           // the rotation for next time.
7131           bump_up++;
7132         }
7133         break;
7134     }   // End of switch
7135     count++;
7136   }   // End of while loop
7137 
7138   if (done)
7139   {
7140     // We found an unproto path.  Check it for accepted values.
7141     // Output a warning message if it is beyond normal ranges,
7142     // but still allow it to be used.
7143     //
7144     if(check_unproto_path(unproto_path_txt))
7145     {
7146       popup_message_always(langcode("WPUPCFT045"),
7147                            langcode("WPUPCFT043"));
7148     }
7149   }
7150   else
7151   {
7152     // We found no entries in the unproto fields for the
7153     // interface.  Set a default path of "WIDE2-2".
7154 
7155     xastir_snprintf(unproto_path_txt,
7156                     sizeof(unproto_path_txt),
7157                     "WIDE2-2");
7158   }
7159 
7160   // Increment the path number for the next round of
7161   // transmissions.  This will round-robin the paths so that all
7162   // entered paths get used.
7163   devices[port].unprotonum = (devices[port].unprotonum + 1 + bump_up) % 3;
7164 
7165   // Make sure the path is in upper-case
7166   (void)to_upper(unproto_path_txt);
7167 
7168   return((unsigned char *)unproto_path_txt);
7169 }
7170 
7171 
7172 
7173 
7174 
7175 //***********************************************************
7176 // output_my_aprs_data
7177 // This is the function responsible for sending out my own
7178 // posits.  The next function below this one handles objects,
7179 // messages and the like (output_my_data).
7180 //***********************************************************
output_my_aprs_data(void)7181 void output_my_aprs_data(void)
7182 {
7183   char header_txt[MAX_LINE_SIZE+5];
7184   char header_txt_save[MAX_LINE_SIZE+5];
7185   char data_txt[MAX_LINE_SIZE+5];
7186   char data_txt_save[MAX_LINE_SIZE+5];
7187   char temp[MAX_LINE_SIZE+5];
7188   char path_txt[MAX_LINE_SIZE+5];
7189   char *unproto_path = "";
7190   char data_txt2[5];
7191   struct tm *day_time;
7192   time_t sec;
7193   char my_pos[256];
7194   char my_output_lat[MAX_LAT];
7195   char my_output_long[MAX_LONG];
7196   char output_net[256];
7197   char wx_data[200];
7198   char output_phg[10];
7199   char output_cs[10];
7200   char output_alt[20];
7201   char output_brk[3];
7202   int ok;
7203   int port;
7204   char my_comment_tx[MAX_COMMENT+1];
7205   int interfaces_ok_for_transmit = 0;
7206   char logfile_tmp_path[MAX_VALUE];
7207 
7208   // Check whether transmits are disabled globally
7209   if (transmit_disable)
7210   {
7211 
7212     if (emergency_beacon)
7213     {
7214 
7215       // Notify the operator because emergency_beacon mode is on but
7216       // nobody will know it 'cuz global transmit is disabled.
7217       //
7218       // "Warning"
7219       // "Global transmit is DISABLED.  Emergency beacons are NOT going out!"
7220       popup_message_always( langcode("POPEM00035"),
7221                             langcode("POPEM00047") );
7222     }
7223     return;
7224   }
7225 
7226   header_txt_save[0] = '\0';
7227   data_txt_save[0] = '\0';
7228   sec = sec_now();
7229 
7230 
7231   // Check whether we're in emergency beacon mode.  If so, add
7232   // "EMERGENCY" at the beginning of the comment field we'll
7233   // transmit.
7234   if (emergency_beacon)
7235   {
7236     strncpy(my_comment_tx, "EMERGENCY", sizeof(my_comment_tx));
7237     my_comment_tx[sizeof(my_comment_tx)-1] = '\0';  // Terminate string
7238   }
7239   else
7240   {
7241     xastir_snprintf(my_comment_tx,
7242                     sizeof(my_comment_tx),
7243                     "%s",
7244                     my_comment);
7245   }
7246 
7247 
7248   // Format latitude string for transmit later
7249   if (transmit_compressed_posit)      // High res version
7250   {
7251     xastir_snprintf(my_output_lat,
7252                     sizeof(my_output_lat),
7253                     "%s",
7254                     my_lat);
7255   }
7256   else    // Create a low-res version of the latitude string
7257   {
7258     long my_temp_lat;
7259     char temp_data[20];
7260 
7261     // Convert to long
7262     my_temp_lat = convert_lat_s2l(my_lat);
7263 
7264     // Convert to low-res string
7265     convert_lat_l2s(my_temp_lat,
7266                     temp_data,
7267                     sizeof(temp_data),
7268                     CONVERT_LP_NORMAL);
7269 
7270     xastir_snprintf(my_output_lat,
7271                     sizeof(my_output_lat),
7272                     "%c%c%c%c.%c%c%c",
7273                     temp_data[0],
7274                     temp_data[1],
7275                     temp_data[3],
7276                     temp_data[4],
7277                     temp_data[6],
7278                     temp_data[7],
7279                     temp_data[8]);
7280   }
7281 
7282   (void)output_lat(my_output_lat,transmit_compressed_posit);
7283   if (debug_level & 128)
7284   {
7285     fprintf(stderr,"OUT LAT <%s>\n",my_output_lat);
7286   }
7287 
7288   // Format longitude string for transmit later
7289   if (transmit_compressed_posit)      // High res version
7290   {
7291     xastir_snprintf(my_output_long,
7292                     sizeof(my_output_long),
7293                     "%s",
7294                     my_long);
7295   }
7296   else    // Create a low-res version of the longitude string
7297   {
7298     long my_temp_long;
7299     char temp_data[20];
7300 
7301     // Convert to long
7302     my_temp_long = convert_lon_s2l(my_long);
7303 
7304     // Convert to low-res string
7305     convert_lon_l2s(my_temp_long,
7306                     temp_data,
7307                     sizeof(temp_data),
7308                     CONVERT_LP_NORMAL);
7309 
7310     xastir_snprintf(my_output_long,
7311                     sizeof(my_output_long),
7312                     "%c%c%c%c%c.%c%c%c",
7313                     temp_data[0],
7314                     temp_data[1],
7315                     temp_data[2],
7316                     temp_data[4],
7317                     temp_data[5],
7318                     temp_data[7],
7319                     temp_data[8],
7320                     temp_data[9]);
7321   }
7322 
7323   (void)output_long(my_output_long,transmit_compressed_posit);
7324   if (debug_level & 128)
7325   {
7326     fprintf(stderr,"OUT LONG <%s>\n",my_output_long);
7327   }
7328 
7329   output_net[0]='\0'; // Make sure this array at least starts initialized.
7330 
7331   begin_critical_section(&devices_lock, "interface.c:output_my_aprs_data" );
7332 
7333   // Iterate across the ports, set up each device's headers/paths/handshakes,
7334   // then transmit the posit if the port is open and tx is enabled.
7335   for (port = 0; port < MAX_IFACE_DEVICES; port++)
7336   {
7337 
7338     // First send any header/path info we might need out the port,
7339     // set up TNC's to the proper mode, etc.
7340     ok = 1;
7341     switch (port_data[port].device_type)
7342     {
7343 
7344       //            case DEVICE_NET_DATABASE:
7345 
7346       case DEVICE_NET_AGWPE:
7347 
7348         output_net[0]='\0'; // We don't need this header for AGWPE
7349         break;
7350 
7351       case DEVICE_NET_STREAM:
7352 
7353         xastir_snprintf(output_net,
7354                         sizeof(output_net),
7355                         "%s>%s,TCPIP*:",
7356                         my_callsign,
7357                         VERSIONFRM);
7358         break;
7359 
7360       case DEVICE_SERIAL_TNC_HSP_GPS:
7361         /* make dtr normal (talk to TNC) */
7362         if (port_data[port].status == DEVICE_UP)
7363         {
7364           port_dtr(port,0);
7365         }
7366       /* Falls through. */
7367 
7368       case DEVICE_SERIAL_TNC_AUX_GPS:
7369       case DEVICE_SERIAL_KISS_TNC:
7370       case DEVICE_SERIAL_MKISS_TNC:
7371       case DEVICE_SERIAL_TNC:
7372       case DEVICE_AX25_TNC:
7373 
7374         /* clear this for a TNC */
7375         output_net[0] = '\0';
7376 
7377         /* Set my call sign */
7378         xastir_snprintf(header_txt,
7379                         sizeof(header_txt),
7380                         "%c%s %s\r",
7381                         '\3',
7382                         "MYCALL",
7383                         my_callsign);
7384 
7385         // Send the callsign out to the TNC only if the interface is up and tx is enabled???
7386         // We don't set it this way for KISS TNC interfaces.
7387         if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
7388              && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
7389              && (port_data[port].status == DEVICE_UP)
7390              && (devices[port].transmit_data == 1)
7391              && !transmit_disable
7392              && !posit_tx_disable)
7393         {
7394           port_write_string(port,header_txt);
7395         }
7396 
7397         // Set unproto path:  Get next unproto path in
7398         // sequence.
7399         unproto_path = (char *)select_unproto_path(port);
7400 
7401         xastir_snprintf(header_txt,
7402                         sizeof(header_txt),
7403                         "%c%s %s VIA %s\r",
7404                         '\3',
7405                         "UNPROTO",
7406                         VERSIONFRM,
7407                         unproto_path);
7408 
7409         xastir_snprintf(header_txt_save,
7410                         sizeof(header_txt_save),
7411                         "%s>%s,%s:",
7412                         my_callsign,
7413                         VERSIONFRM,
7414                         unproto_path);
7415 
7416         xastir_snprintf(path_txt,
7417                         sizeof(path_txt),
7418                         "%s",
7419                         unproto_path);
7420 
7421 
7422         // Send the header data to the TNC.  This sets the
7423         // unproto path that'll be used by the next packet.
7424         // We don't set it this way for KISS TNC interfaces.
7425         if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
7426              && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
7427              && (port_data[port].status == DEVICE_UP)
7428              && (devices[port].transmit_data == 1)
7429              && !transmit_disable
7430              && !posit_tx_disable)
7431         {
7432           port_write_string(port,header_txt);
7433         }
7434 
7435 
7436         // Set converse mode.  We don't need to do this for
7437         // KISS TNC interfaces.  One european TNC (tnc2-ui)
7438         // doesn't accept "conv" but does accept the 'k'
7439         // command.  A Kantronics KPC-2 v2.71 TNC accepts
7440         // the "conv" command but not the 'k' command.
7441         // Figures!  The  choice of whether to send "k" or "conv"
7442         // is made by the user in the Serial TNC interface properties
7443         // dialog.  Older versions of Xastir had this hardcoded here.
7444         //
7445         xastir_snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', devices[port].device_converse_string);
7446 
7447         if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
7448              && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
7449              && (port_data[port].status == DEVICE_UP)
7450              && (devices[port].transmit_data == 1)
7451              && !transmit_disable
7452              && !posit_tx_disable)
7453         {
7454           port_write_string(port,header_txt);
7455         }
7456         // Delay a bit if the user clicked on the "Add Delay"
7457         // togglebutton in the port's interface properties dialog.
7458         // This is primarily needed for KAM TNCs, which will fail to
7459         // go into converse mode if there is no delay here.
7460         if (devices[port].tnc_extra_delay != 0)
7461         {
7462           usleep(devices[port].tnc_extra_delay);
7463         }
7464         break;
7465 
7466       default: /* port has unknown device_type */
7467         ok = 0;
7468         break;
7469 
7470     } // End of switch
7471 
7472 
7473     // Set up some more strings for later transmission
7474 
7475     /* send station info */
7476     output_cs[0] = '\0';
7477     output_phg[0] = '\0';
7478     output_alt[0] = '\0';
7479     output_brk[0] = '\0';
7480 
7481 
7482     if (transmit_compressed_posit)
7483       xastir_snprintf(my_pos,
7484                       sizeof(my_pos),
7485                       "%s",
7486                       compress_posit(my_output_lat,
7487                                      my_group,
7488                                      my_output_long,
7489                                      my_symbol,
7490                                      my_last_course,
7491                                      my_last_speed,  // In knots
7492                                      my_phg));
7493     else   /* standard non compressed mode */
7494     {
7495       xastir_snprintf(my_pos,
7496                       sizeof(my_pos),
7497                       "%s%c%s%c",
7498                       my_output_lat,
7499                       my_group,
7500                       my_output_long,
7501                       my_symbol);
7502       /* get PHG, if used for output */
7503       if (strlen(my_phg) >= 6)
7504         xastir_snprintf(output_phg,
7505                         sizeof(output_phg),
7506                         "%s",
7507                         my_phg);
7508 
7509       /* get CSE/SPD, Always needed for output even if 0 */
7510       xastir_snprintf(output_cs,
7511                       sizeof(output_cs),
7512                       "%03d/%03d/",
7513                       my_last_course,
7514                       my_last_speed);    // Speed in knots
7515 
7516       /* get altitude */
7517       if (my_last_altitude_time > 0)
7518         xastir_snprintf(output_alt,
7519                         sizeof(output_alt),
7520                         "A=%06ld/",
7521                         my_last_altitude);
7522     }
7523 
7524 
7525     // And set up still more strings for later transmission
7526     switch (output_station_type)
7527     {
7528       case(1):
7529         /* APRS_MOBILE LOCAL TIME */
7530 
7531         if((strlen(output_cs) < 8) && (my_last_altitude_time > 0) &&
7532             (strlen(output_alt) > 0))
7533         {
7534           xastir_snprintf(output_brk,
7535                           sizeof(output_brk),
7536                           "/");
7537         }
7538 
7539         day_time = localtime(&sec);
7540 
7541         xastir_snprintf(data_txt_save,
7542                         sizeof(data_txt_save),
7543                         "@%02d%02d%02d/%s%s%s%s%s",
7544                         day_time->tm_mday,
7545                         day_time->tm_hour,
7546                         day_time->tm_min,
7547                         my_pos,
7548                         output_cs,
7549                         output_brk,
7550                         output_alt,
7551                         my_comment_tx);
7552 
7553         //WE7U2:
7554         // Truncate at max length for this type of APRS
7555         // packet.
7556         if (transmit_compressed_posit)
7557         {
7558           if (strlen(data_txt_save) > 61)
7559           {
7560             data_txt_save[61] = '\0';
7561           }
7562         }
7563         else   // Uncompressed lat/long
7564         {
7565           if (strlen(data_txt_save) > 70)
7566           {
7567             data_txt_save[70] = '\0';
7568           }
7569         }
7570 
7571         // Add '\r' onto end.
7572         strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7573 
7574         strcpy(data_txt, output_net);
7575         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7576 
7577         strcat(data_txt, data_txt_save);
7578         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7579 
7580         break;
7581 
7582       case(2):
7583         /* APRS_MOBILE ZULU DATE-TIME */
7584 
7585         if((strlen(output_cs) < 8) && (my_last_altitude_time > 0) &&
7586             (strlen(output_alt) > 0))
7587         {
7588           xastir_snprintf(output_brk,
7589                           sizeof(output_brk),
7590                           "/");
7591         }
7592 
7593         day_time = gmtime(&sec);
7594 
7595         xastir_snprintf(data_txt_save,
7596                         sizeof(data_txt_save),
7597                         "@%02d%02d%02dz%s%s%s%s%s",
7598                         day_time->tm_mday,
7599                         day_time->tm_hour,
7600                         day_time->tm_min,
7601                         my_pos,
7602                         output_cs,
7603                         output_brk,
7604                         output_alt,
7605                         my_comment_tx);
7606 
7607         //WE7U2:
7608         // Truncate at max length for this type of APRS
7609         // packet.
7610         if (transmit_compressed_posit)
7611         {
7612           if (strlen(data_txt_save) > 61)
7613           {
7614             data_txt_save[61] = '\0';
7615           }
7616         }
7617         else   // Uncompressed lat/long
7618         {
7619           if (strlen(data_txt_save) > 70)
7620           {
7621             data_txt_save[70] = '\0';
7622           }
7623         }
7624 
7625         // Add '\r' onto end.
7626         strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7627 
7628         strcpy(data_txt, output_net);
7629         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7630 
7631         strcat(data_txt, data_txt_save);
7632         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7633 
7634         break;
7635 
7636       case(3):
7637         /* APRS_MOBILE ZULU TIME w/SEC */
7638 
7639         if((strlen(output_cs) < 8) && (my_last_altitude_time > 0) &&
7640             (strlen(output_alt) > 0))
7641         {
7642           xastir_snprintf(output_brk,
7643                           sizeof(output_brk),
7644                           "/");
7645         }
7646 
7647         day_time = gmtime(&sec);
7648 
7649         xastir_snprintf(data_txt_save,
7650                         sizeof(data_txt_save),
7651                         "@%02d%02d%02dh%s%s%s%s%s",
7652                         day_time->tm_hour,
7653                         day_time->tm_min,
7654                         day_time->tm_sec,
7655                         my_pos,
7656                         output_cs,
7657                         output_brk,
7658                         output_alt,
7659                         my_comment_tx);
7660 
7661         //WE7U2:
7662         // Truncate at max length for this type of APRS
7663         // packet.
7664         if (transmit_compressed_posit)
7665         {
7666           if (strlen(data_txt_save) > 61)
7667           {
7668             data_txt_save[61] = '\0';
7669           }
7670         }
7671         else   // Uncompressed lat/long
7672         {
7673           if (strlen(data_txt_save) > 70)
7674           {
7675             data_txt_save[70] = '\0';
7676           }
7677         }
7678 
7679         // Add '\r' onto end.
7680         strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7681 
7682         strcpy(data_txt, output_net);
7683         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7684 
7685         strcat(data_txt, data_txt_save);
7686         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7687 
7688         break;
7689 
7690       case(4):
7691         /* APRS position with WX data, no timestamp */
7692         sec = wx_tx_data1(wx_data, sizeof(wx_data));
7693         if (sec != 0)
7694         {
7695 
7696           xastir_snprintf(data_txt_save,
7697                           sizeof(data_txt_save),
7698                           "%c%s%s",
7699                           aprs_station_message_type,
7700                           my_pos,
7701                           wx_data);
7702 
7703           // WE7U2:
7704           // There's no limit on the max size for this kind of packet except
7705           // for the AX.25 limit of 256 bytes!
7706           //
7707           // Truncate at max length for this type of APRS
7708           // packet.  Left the compressed/uncompressed
7709           // "if" statement here in case we need to change
7710           // this in the future due to spec changes.
7711           // Consistent with the rest of the code in this
7712           // function which does similar things.
7713           //
7714           if (transmit_compressed_posit)
7715           {
7716             if (strlen(data_txt_save) > 256)
7717             {
7718               data_txt_save[256] = '\0';
7719             }
7720           }
7721           else   // Uncompressed lat/long
7722           {
7723             if (strlen(data_txt_save) > 256)
7724             {
7725               data_txt_save[256] = '\0';
7726             }
7727           }
7728 
7729           // Add '\r' onto end.
7730           strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7731 
7732           strcpy(data_txt, output_net);
7733           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7734 
7735           strcat(data_txt, data_txt_save);
7736           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7737         }
7738         else
7739         {
7740           /* default to APRS FIXED if no wx data. No timestamp */
7741 
7742           if ((strlen(output_phg) < 6) && (my_last_altitude_time > 0) &&
7743               (strlen(output_alt) > 0))
7744           {
7745             xastir_snprintf(output_brk,
7746                             sizeof(output_brk),
7747                             "/");
7748           }
7749 
7750           xastir_snprintf(data_txt_save,
7751                           sizeof(data_txt_save),
7752                           "%c%s%s%s%s%s",
7753                           aprs_station_message_type,
7754                           my_pos,
7755                           output_phg,
7756                           output_brk,
7757                           output_alt,
7758                           my_comment_tx);
7759 
7760           // WE7U2:
7761           // Truncate at max length for this type of APRS
7762           // packet.
7763           if (transmit_compressed_posit)
7764           {
7765             if (strlen(data_txt_save) > 54)
7766             {
7767               data_txt_save[54] = '\0';
7768             }
7769           }
7770           else   // Uncompressed lat/long
7771           {
7772             if (strlen(data_txt_save) > 63)
7773             {
7774               data_txt_save[63] = '\0';
7775             }
7776           }
7777 
7778           // Add '\r' onto end.
7779           strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7780 
7781           strcpy(data_txt, output_net);
7782           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7783 
7784           strcat(data_txt, data_txt_save);
7785           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7786         }
7787 
7788         break;
7789 
7790       case(5):
7791         /* APRS position with ZULU DATE-TIME and WX data */
7792         sec = wx_tx_data1(wx_data,sizeof(wx_data));
7793         if (sec != 0)
7794         {
7795           day_time = gmtime(&sec);
7796 
7797           xastir_snprintf(data_txt_save,
7798                           sizeof(data_txt_save),
7799                           "@%02d%02d%02dz%s%s",
7800                           day_time->tm_mday,
7801                           day_time->tm_hour,
7802                           day_time->tm_min,
7803                           my_pos,
7804                           wx_data);
7805 
7806           // WE7U2:
7807           // Truncate at max length for this type of APRS
7808           // packet.
7809           if (transmit_compressed_posit)
7810           {
7811             if (strlen(data_txt_save) > 61)
7812             {
7813               data_txt_save[61] = '\0';
7814             }
7815           }
7816           else   // Uncompressed lat/long
7817           {
7818             if (strlen(data_txt_save) > 70)
7819             {
7820               data_txt_save[70] = '\0';
7821             }
7822           }
7823 
7824           // Add '\r' onto end.
7825           strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7826 
7827           strcpy(data_txt, output_net);
7828           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7829 
7830           strcat(data_txt, data_txt_save);
7831           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7832         }
7833         else
7834         {
7835           /* default to APRS FIXED if no wx data */
7836 
7837           if((strlen(output_phg) < 6) && (my_last_altitude_time > 0) &&
7838               (strlen(output_alt) > 0))
7839           {
7840             xastir_snprintf(output_brk,
7841                             sizeof(output_brk),
7842                             "/");
7843           }
7844 
7845           xastir_snprintf(data_txt_save,
7846                           sizeof(data_txt_save),
7847                           "%c%s%s%s%s%s",
7848                           aprs_station_message_type,
7849                           my_pos,
7850                           output_phg,
7851                           output_brk,
7852                           output_alt,
7853                           my_comment_tx);
7854 
7855           // WE7U2:
7856           // Truncate at max length for this type of APRS
7857           // packet.
7858           if (transmit_compressed_posit)
7859           {
7860             if (strlen(data_txt_save) > 54)
7861             {
7862               data_txt_save[54] = '\0';
7863             }
7864           }
7865           else   // Uncompressed lat/long
7866           {
7867             if (strlen(data_txt_save) > 63)
7868             {
7869               data_txt_save[63] = '\0';
7870             }
7871           }
7872 
7873           // Add '\r' onto end.
7874           strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7875 
7876           strcpy(data_txt, output_net);
7877           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7878 
7879           strcat(data_txt, data_txt_save);
7880           data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7881         }
7882         break;
7883 
7884       /* default to APRS FIXED if no wx data */
7885       case(0):
7886 
7887       default:
7888         /* APRS_FIXED */
7889 
7890         if ((strlen(output_phg) < 6) && (my_last_altitude_time > 0) &&
7891             (strlen(output_alt) > 0))
7892         {
7893           xastir_snprintf(output_brk,
7894                           sizeof(output_brk),
7895                           "/");
7896         }
7897 
7898         xastir_snprintf(data_txt_save,
7899                         sizeof(data_txt_save),
7900                         "%c%s%s%s%s%s",
7901                         aprs_station_message_type,
7902                         my_pos,
7903                         output_phg,
7904                         output_brk,
7905                         output_alt,
7906                         my_comment_tx);
7907 
7908         // WE7U2:
7909         // Truncate at max length for this type of APRS
7910         // packet.
7911         if (transmit_compressed_posit)
7912         {
7913           if (strlen(data_txt_save) > 54)
7914           {
7915             data_txt_save[54] = '\0';
7916           }
7917         }
7918         else   // Uncompressed lat/long
7919         {
7920           if (strlen(data_txt_save) > 63)
7921           {
7922             data_txt_save[63] = '\0';
7923           }
7924         }
7925 
7926         // Add '\r' onto end.
7927         strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1);
7928 
7929         strcpy(data_txt, output_net);
7930         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7931 
7932         strcat(data_txt, data_txt_save);
7933         data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
7934 
7935         break;
7936     }
7937 
7938     if (ok)
7939     {
7940       // Here's where the actual transmit of the posit occurs.  The
7941       // transmit string has been set up in "data_txt" by this point.
7942 
7943       // If transmit or posits have been turned off, don't transmit posit
7944       if ( (port_data[port].status == DEVICE_UP)
7945            && (devices[port].transmit_data == 1)
7946            && !transmit_disable
7947            && !posit_tx_disable)
7948       {
7949 
7950         interfaces_ok_for_transmit++;
7951 
7952         // WE7U:  Change so that path is passed as well for KISS TNC
7953         // interfaces:  header_txt_save would probably be the one to pass,
7954         // or create a new string just for KISS TNC's.
7955 
7956         if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC)
7957              || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) )
7958         {
7959 
7960           // Note:  This one has callsign & destination in the string
7961 
7962           // Transmit the posit out the KISS interface
7963           send_ax25_frame(port,
7964                           my_callsign,    // source
7965                           VERSIONFRM,     // destination
7966                           path_txt,       // path
7967                           data_txt);      // data
7968         }
7969 
7970         //WE7U:AGWPE
7971         else if (port_data[port].device_type == DEVICE_NET_AGWPE)
7972         {
7973 
7974           // Set unproto path:  Get next unproto path in
7975           // sequence.
7976           unproto_path = (char *)select_unproto_path(port);
7977 
7978           // We need to remove the complete AX.25 header from data_txt before
7979           // we call this routine!  Instead put the digipeaters into the
7980           // ViaCall fields.  We do this above by setting output_net to '\0'
7981           // before creating the data_txt string.
7982           send_agwpe_packet(port,            // Xastir interface port
7983                             atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort
7984                             '\0',                          // Type of frame
7985                             (unsigned char *)my_callsign,  // source
7986                             (unsigned char *)VERSIONFRM,   // destination
7987                             (unsigned char *)unproto_path, // Path,
7988                             (unsigned char *)data_txt,     // Data
7989                             strlen(data_txt) - 1);         // Skip \r
7990         }
7991 
7992         else
7993         {
7994           // Not a Serial KISS TNC interface
7995           port_write_string(port, data_txt);  // Transmit the posit
7996         }
7997 
7998         if (debug_level & 2)
7999         {
8000           fprintf(stderr,"TX:%d<%s>\n",port,data_txt);
8001         }
8002 
8003         /* add new line on network data */
8004         if (port_data[port].device_type == DEVICE_NET_STREAM)
8005         {
8006           xastir_snprintf(data_txt2, sizeof(data_txt2), "\n");                 // Transmit a newline
8007           port_write_string(port, data_txt2);
8008         }
8009 
8010 
8011         // Put our transmitted packet into the Incoming Data
8012         // window as well.  This way we can see both sides of a
8013         // conversation.  data_port == -1 for x_spider port,
8014         // normal interface number otherwise.  -99 to get a "**"
8015         // display meaning all ports.
8016         //
8017         // For packets that we're igating we end up with a CR or
8018         // LF on the end of them.  Remove that so the display
8019         // looks nice.
8020         strcpy(temp, my_callsign);
8021         temp[sizeof(temp)-1] = '\0';  // Terminate string
8022         strcat(temp, ">");
8023         temp[sizeof(temp)-1] = '\0';  // Terminate string
8024         strcat(temp, VERSIONFRM);
8025         temp[sizeof(temp)-1] = '\0';  // Terminate string
8026         strcat(temp, ",");
8027         temp[sizeof(temp)-1] = '\0';  // Terminate string
8028         strcat(temp, unproto_path);
8029         temp[sizeof(temp)-1] = '\0';  // Terminate string
8030         strcat(temp, ":");
8031         temp[sizeof(temp)-1] = '\0';  // Terminate string
8032         strcat(temp, data_txt);
8033         temp[sizeof(temp)-1] = '\0';  // Terminate string
8034 
8035         makePrintable(temp);
8036         packet_data_add("TX ", temp, port);
8037       }
8038       else
8039       {
8040       }
8041     } // End of posit transmit: "if (ok)"
8042   } // End of big loop
8043 
8044   end_critical_section(&devices_lock, "interface.c:output_my_aprs_data" );
8045 
8046 
8047   // Check the interfaces_ok_for_transmit variable if we're in
8048   // emergency_beacon mode.  If we didn't transmit out any interfaces, alert
8049   // the operator so that they can either enable interfaces or get emergency
8050   // help in some other manner.
8051   //
8052   if (emergency_beacon)
8053   {
8054 
8055     if (interfaces_ok_for_transmit)
8056     {
8057 
8058       // Beacons are going out in emergency beacon mode.  Alert the
8059       // operator so that he/she knows they've enabled that mode.
8060       //
8061       // "Emergency Beacon Mode"
8062       // "EMERGENCY BEACON MODE, transmitting every 60 seconds!"
8063       popup_message_always( langcode("POPEM00048"),
8064                             langcode("POPEM00049") );
8065     }
8066 
8067     else    // Emergency beacons are not going out for some reason
8068     {
8069 
8070       // Notify the operator because emergency_beacon mode is on but
8071       // nobody will know it 'cuz there are no interfaces enabled for
8072       // transmit.
8073       //
8074       // "Warning"
8075       // "Interfaces or posits/transmits DISABLED.  Emergency beacons are NOT going out!"
8076       popup_message_always( langcode("POPEM00035"),
8077                             langcode("POPEM00050") );
8078     }
8079   }
8080 
8081 
8082   // This will log a posit in the general format for a network interface
8083   // whether or not any network interfaces are currently up.
8084   if (log_net_data)
8085   {
8086 
8087     strcpy(data_txt, my_callsign);
8088     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8089     strcat(data_txt, ">");
8090     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8091     strcat(data_txt, VERSIONFRM);
8092     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8093     strcat(data_txt, ",TCPIP*:");
8094     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8095     strcat(data_txt, data_txt_save);
8096     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8097 
8098     log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path,
8099                                 sizeof(logfile_tmp_path)),
8100               (char *)data_txt );
8101   }
8102 
8103 
8104   if (enable_server_port && !transmit_disable && !posit_tx_disable)
8105   {
8106     // Send data to the x_spider server
8107 
8108     strcpy(data_txt, my_callsign);
8109     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8110     strcat(data_txt, ">");
8111     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8112     strcat(data_txt, VERSIONFRM);
8113     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8114     strcat(data_txt, ",TCPIP*:");
8115     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8116     strcat(data_txt, data_txt_save);
8117     data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8118 
8119     if (writen(pipe_xastir_to_tcp_server,
8120                data_txt,
8121                strlen(data_txt)) != (int)strlen(data_txt))
8122     {
8123       fprintf(stderr,
8124               "my_aprs_data: Writen error: %d\n",
8125               errno);
8126     }
8127     // Terminate it with a linefeed
8128     if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1)
8129     {
8130       fprintf(stderr,
8131               "my_aprs_data: Writen error: %d\n",
8132               errno);
8133     }
8134   }
8135   // End of x_spider server send code
8136 
8137 
8138   // Note that this will only log one TNC line per transmission now matter
8139   // how many TNC's are defined.  It's a representative sample of what we're
8140   // sending out.  At least one TNC interface must be enabled in order to
8141   // have anything output to the log file here.
8142   if (log_tnc_data)
8143   {
8144     if (header_txt_save[0] != '\0')
8145     {
8146 
8147       strcpy(data_txt, header_txt_save);
8148       data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8149       strcat(data_txt, data_txt_save);
8150       data_txt[sizeof(data_txt)-1] = '\0';  // Terminate string
8151 
8152       log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path,
8153                                   sizeof(logfile_tmp_path)),
8154                 (char *)data_txt );
8155     }
8156   }
8157 }
8158 
8159 
8160 
8161 
8162 
8163 //*****************************************************************************
8164 // output_my_data()
8165 //
8166 // 1) Used to send local messages/objects/items.  Cooked mode.
8167 // 2) Used from output_igate_net(), igating from RF to the 'net.  Raw mode.
8168 // 3) Used from output_igate_rf() to igate from the 'net to RF.  Cooked mode.
8169 // 4) Used from output_nws_igate_rf() to send NWS packets out RF.  Cooked mode.
8170 // 5) Used for queries and responses.  Cooked mode.
8171 //
8172 // Parameters:
8173 // message: the message data to send
8174 // port: the port transmitting through, or -1 for all
8175 // type: 0 for my data, 1 for raw data (Cooked/Raw)
8176 // loopback_only: 0 for transmit/loopback, 1 for loopback only
8177 // use_igate_path: 0 for standard unproto paths, 1 for igate path
8178 // path: Set to non-NULL if special path selected for messaging
8179 //
8180 // This function sends out messages/objects/bulletins/etc.
8181 // This one currently tries to do local logging even if
8182 // transmit is disabled.
8183 //*****************************************************************************
output_my_data(char * message,int incoming_port,int type,int loopback_only,int use_igate_path,char * path)8184 void output_my_data(char *message, int incoming_port, int type, int loopback_only, int use_igate_path, char *path)
8185 {
8186   char data_txt[MAX_LINE_SIZE+5];
8187   char data_txt_save[MAX_LINE_SIZE+5];
8188   char temp[MAX_LINE_SIZE+5];
8189   char path_txt[MAX_LINE_SIZE+5];
8190   char *unproto_path = "";
8191   char output_net[256];
8192   int ok, start, finish, port;
8193   int done;
8194   char logfile_tmp_path[MAX_VALUE];
8195 
8196   // Check whether transmits are disabled globally
8197   if (transmit_disable && !loopback_only)
8198   {
8199     return;
8200   }
8201 
8202   //// cbell- if path is null, strlen/printf segv in solaris
8203   if (path == NULL)
8204   {
8205     path = "";
8206   }
8207 
8208   if (debug_level & 1)
8209   {
8210     fprintf(stderr,
8211             "Sending out port: %d, type: %d, path: %s\n",
8212             incoming_port,
8213             type,
8214             path);
8215   }
8216 
8217   if (message == NULL)
8218   {
8219     return;
8220   }
8221 
8222   if (message[0] == '\0')
8223   {
8224     return;
8225   }
8226 
8227   data_txt_save[0] = '\0';
8228 
8229   if (incoming_port == -1)     // Send out all of the interfaces
8230   {
8231     start = 0;
8232     finish = MAX_IFACE_DEVICES;
8233   }
8234   else    // Only send out the chosen interface
8235   {
8236     start  = incoming_port;
8237     finish = incoming_port + 1;
8238   }
8239 
8240 
8241   begin_critical_section(&devices_lock, "interface.c:output_my_data" );
8242 
8243   for (port = start; port < finish; port++)
8244   {
8245 
8246     ok = 1;
8247     if (type == 0)                          // my data
8248     {
8249       switch (port_data[port].device_type)
8250       {
8251 
8252         //                case DEVICE_NET_DATABASE:
8253 
8254         case DEVICE_NET_AGWPE:
8255           output_net[0] = '\0';   // Clear header
8256           break;
8257 
8258         case DEVICE_NET_STREAM:
8259           if (debug_level & 1)
8260           {
8261             fprintf(stderr,"%d Net\n",port);
8262           }
8263           xastir_snprintf(output_net,
8264                           sizeof(output_net),
8265                           "%s>%s,TCPIP*:",
8266                           my_callsign,
8267                           VERSIONFRM);
8268           break;
8269 
8270         case DEVICE_SERIAL_TNC_HSP_GPS:
8271           if (port_data[port].status == DEVICE_UP && !loopback_only && !transmit_disable)
8272           {
8273             port_dtr(port,0);           // make DTR normal (talk to TNC)
8274           }
8275         /* Falls through. */
8276 
8277         case DEVICE_SERIAL_TNC_AUX_GPS:
8278         case DEVICE_SERIAL_KISS_TNC:
8279         case DEVICE_SERIAL_MKISS_TNC:
8280         case DEVICE_SERIAL_TNC:
8281         case DEVICE_AX25_TNC:
8282 
8283           if (debug_level & 1)
8284           {
8285             fprintf(stderr,"%d AX25 TNC\n",port);
8286           }
8287           output_net[0] = '\0';   // clear this for a TNC
8288 
8289           /* Set my call sign */
8290           xastir_snprintf(data_txt,
8291                           sizeof(data_txt),
8292                           "%c%s %s\r",
8293                           '\3',
8294                           "MYCALL",
8295                           my_callsign);
8296 
8297           if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
8298                && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
8299                && (port_data[port].status == DEVICE_UP)
8300                && (devices[port].transmit_data == 1)
8301                && !transmit_disable
8302                && !loopback_only)
8303           {
8304             port_write_string(port,data_txt);
8305             usleep(10000);  // 10ms
8306           }
8307 
8308           done = 0;
8309 
8310           // Set unproto path.  First check whether we're
8311           // to use the igate path.  If so and the path
8312           // isn't empty, skip the rest of the path selection:
8313           if ( (use_igate_path)
8314                && (strlen(devices[port].unproto_igate) > 0) )
8315           {
8316 
8317             // WE7U:  Should we check here and in the following path
8318             // selection code to make sure that there are printable characters
8319             // in the path?  Also:  Output_my_aprs_data() has nearly identical
8320             // path selection code.  Fix it in one place, fix it in the other.
8321 
8322             // Check whether igate path is socially
8323             // acceptable.  Output warning if not, but
8324             // still allow the transmit.
8325             if(check_unproto_path(devices[port].unproto_igate))
8326             {
8327               popup_message_always(langcode("WPUPCFT046"),
8328                                    langcode("WPUPCFT043"));
8329             }
8330 
8331             xastir_snprintf(data_txt,
8332                             sizeof(data_txt),
8333                             "%c%s %s VIA %s\r",
8334                             '\3',
8335                             "UNPROTO",
8336                             VERSIONFRM,
8337                             devices[port].unproto_igate);
8338 
8339             xastir_snprintf(data_txt_save,
8340                             sizeof(data_txt_save),
8341                             "%s>%s,%s:",
8342                             my_callsign,
8343                             VERSIONFRM,
8344                             devices[port].unproto_igate);
8345 
8346             xastir_snprintf(path_txt,
8347                             sizeof(path_txt),
8348                             "%s",
8349                             devices[port].unproto_igate);
8350 
8351             done++;
8352           }
8353 
8354 
8355           // Check whether a path was passed to us as a
8356           // parameter:
8357           if ( (path != NULL) && (strlen(path) != 0) )
8358           {
8359 
8360             if (strncmp(path, "DIRECT PATH", 11) == 0)
8361             {
8362               // The user has requested a direct path
8363 
8364               xastir_snprintf(data_txt,
8365                               sizeof(data_txt),
8366                               "%c%s %s\r",
8367                               '\3',
8368                               "UNPROTO",
8369                               VERSIONFRM);
8370 
8371               xastir_snprintf(data_txt_save,
8372                               sizeof(data_txt_save),
8373                               "%s>%s:",
8374                               my_callsign,
8375                               VERSIONFRM);
8376             }
8377             else
8378             {
8379 
8380               xastir_snprintf(data_txt,
8381                               sizeof(data_txt),
8382                               "%c%s %s VIA %s\r",
8383                               '\3',
8384                               "UNPROTO",
8385                               VERSIONFRM,
8386                               path);
8387 
8388               xastir_snprintf(data_txt_save,
8389                               sizeof(data_txt_save),
8390                               "%s>%s,%s:",
8391                               my_callsign,
8392                               VERSIONFRM,
8393                               path);
8394             }
8395 
8396             if (strncmp(path, "DIRECT PATH", 11) == 0)
8397             {
8398               // The user has requested a direct path
8399               path_txt[0] = '\0'; // Empty path
8400             }
8401             else
8402             {
8403               xastir_snprintf(path_txt,
8404                               sizeof(path_txt),
8405                               "%s",
8406                               path);
8407             }
8408 
8409             done++;
8410 
8411             // If "DEFAULT PATH" was passed to us, then
8412             // we're not done yet.
8413             //
8414             if (strncmp(path, "DEFAULT PATH", 12) == 0)
8415             {
8416               done = 0;
8417             }
8418           }
8419 
8420           if (!done)
8421           {
8422 
8423             // Set unproto path:  Get next unproto path
8424             // in sequence.
8425             unproto_path = (char *)select_unproto_path(port);
8426 
8427             xastir_snprintf(data_txt,
8428                             sizeof(data_txt),
8429                             "%c%s %s VIA %s\r",
8430                             '\3',
8431                             "UNPROTO",
8432                             VERSIONFRM,
8433                             unproto_path);
8434 
8435             xastir_snprintf(data_txt_save,
8436                             sizeof(data_txt_save),
8437                             "%s>%s,%s:",
8438                             my_callsign,
8439                             VERSIONFRM,
8440                             unproto_path);
8441 
8442             xastir_snprintf(path_txt,
8443                             sizeof(path_txt),
8444                             "%s",
8445                             unproto_path);
8446 
8447             done++;
8448           }
8449 
8450 
8451           if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
8452                && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
8453                && (port_data[port].status == DEVICE_UP)
8454                && (devices[port].transmit_data == 1)
8455                && !transmit_disable
8456                && !loopback_only)
8457           {
8458             port_write_string(port,data_txt);
8459             usleep(10000);  // 10ms
8460           }
8461 
8462           // Set converse mode.  One european TNC
8463           // (tnc2-ui) doesn't accept "conv" but does
8464           // accept the 'k' command.  A Kantronics  KPC-2
8465           // v2.71 TNC accepts the "conv" command but not
8466           // the 'k' command.  Figures!
8467           //
8468           //                    xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', "CONV");
8469           //                    xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', "k");
8470           //                    xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', CONVERSE_MODE);
8471           xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', devices[port].device_converse_string);
8472 
8473 
8474 
8475           if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC)
8476                && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC)
8477                && (port_data[port].status == DEVICE_UP)
8478                && (devices[port].transmit_data == 1)
8479                && !transmit_disable
8480                && !loopback_only)
8481           {
8482             port_write_string(port,data_txt);
8483             usleep(20000); // 20ms
8484           }
8485           break;
8486 
8487         default: /* unknown */
8488           ok = 0;
8489           break;
8490       } // End of switch
8491     }
8492     else        // Type == 1, raw data.  Probably igating something...
8493     {
8494       output_net[0] = '\0';
8495     }
8496 
8497 
8498     if (ok)
8499     {
8500       /* send data */
8501       xastir_snprintf(data_txt, sizeof(data_txt), "%s%s\r", output_net, message);
8502       if ( (port_data[port].status == DEVICE_UP)
8503            && (devices[port].transmit_data == 1)
8504            && !transmit_disable
8505            && !loopback_only)
8506       {
8507 
8508         // WE7U:  Change so that path is passed as well for KISS TNC
8509         // interfaces:  data_txt_save would probably be the one to pass,
8510         // or create a new string just for KISS TNC's.
8511 
8512         if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC)
8513              || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) )
8514         {
8515 
8516           // Transmit
8517           send_ax25_frame(port,
8518                           my_callsign,    // source
8519                           VERSIONFRM,     // destination
8520                           path_txt,       // path
8521                           data_txt);      // data
8522         }
8523 
8524         //WE7U:AGWPE
8525         else if (port_data[port].device_type == DEVICE_NET_AGWPE)
8526         {
8527 
8528           // Set unproto path.  First check whether we're
8529           // to use the igate path.  If so and the path
8530           // isn't empty, skip the rest of the path selection:
8531           if ( (use_igate_path)
8532                && (strlen(devices[port].unproto_igate) > 0) )
8533           {
8534 
8535             // Check whether igate path is socially
8536             // acceptable.  Output warning if not, but
8537             // still allow the transmit.
8538             if(check_unproto_path(devices[port].unproto_igate))
8539             {
8540               popup_message_always(langcode("WPUPCFT046"),
8541                                    langcode("WPUPCFT043"));
8542             }
8543 
8544             xastir_snprintf(path_txt,
8545                             sizeof(path_txt),
8546                             "%s",
8547                             devices[port].unproto_igate);
8548           }
8549           // Check whether a path was passed to us as a
8550           // parameter:
8551           else if ( (path != NULL) && (strlen(path) != 0) )
8552           {
8553 
8554             if (strncmp(path, "DEFAULT PATH", 12) == 0)
8555             {
8556               unproto_path = (char *)select_unproto_path(port);
8557 
8558               xastir_snprintf(path_txt,
8559                               sizeof(path_txt),
8560                               "%s",
8561                               unproto_path);
8562             }
8563 
8564             else if (strncmp(path, "DIRECT PATH", 11) == 0)
8565             {
8566               // The user has requested a direct path
8567               path_txt[0] = '\0'; // Empty string
8568 
8569               // WE7U
8570               // TEST THIS TO SEE IF IT WORKS ON AGWPE TO HAVE NO PATH
8571 
8572             }
8573             else
8574             {
8575               xastir_snprintf(path_txt,
8576                               sizeof(path_txt),
8577                               "%s",
8578                               path);
8579             }
8580           }
8581           else
8582           {
8583             // Set unproto path:  Get next unproto path in
8584             // sequence.
8585 
8586             unproto_path = (char *)select_unproto_path(port);
8587 
8588             xastir_snprintf(path_txt,
8589                             sizeof(path_txt),
8590                             "%s",
8591                             unproto_path);
8592           }
8593 
8594           // We need to remove the complete AX.25 header from data_txt before
8595           // we call this routine!  Instead put the digipeaters into the
8596           // ViaCall fields.  We do this above by setting output_net to '\0'
8597           // before creating the data_txt string.
8598 
8599           send_agwpe_packet(port,           // Xastir interface port
8600                             atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort
8601                             '\0',                         // Type of frame
8602                             (unsigned char *)my_callsign, // source
8603                             (unsigned char *)VERSIONFRM,  // destination
8604                             (unsigned char *)path_txt,    // Path,
8605                             (unsigned char *)data_txt,    // Data
8606                             strlen(data_txt) - 1);        // Skip \r
8607         }
8608 
8609         else
8610         {
8611           // Not a Serial KISS TNC interface
8612           port_write_string(port, data_txt);  // Transmit
8613         }
8614 
8615         if (debug_level & 1)
8616           fprintf(stderr,"Sending to interface:%d, %s\n",
8617                   port,
8618                   data_txt);
8619 
8620 
8621         // Put our transmitted packet into the Incoming Data
8622         // window as well.  This way we can see both sides of a
8623         // conversation.  data_port == -1 for x_spider port,
8624         // normal interface number otherwise.  -99 to get a "**"
8625         // display meaning all ports.
8626         //
8627         // For packets that we're igating we end up with a CR or
8628         // LF on the end of them.  Remove that so the display
8629         // looks nice.
8630         //
8631         // Check whether a path was passed to us as a
8632         // parameter:
8633 
8634         if ( (path != NULL) && (strlen(path) != 0) )
8635         {
8636 
8637           if (strncmp(path, "DEFAULT PATH", 12) == 0)
8638           {
8639             xastir_snprintf(temp,
8640                             sizeof(temp),
8641                             "%s>%s,%s:%s",
8642                             my_callsign,
8643                             VERSIONFRM,
8644                             unproto_path,
8645                             message);
8646           }
8647           else if (strncmp(path, "DIRECT PATH", 11) == 0)
8648           {
8649             // The user has requested a direct path
8650             xastir_snprintf(temp,
8651                             sizeof(temp),
8652                             "%s>%s:%s",
8653                             my_callsign,
8654                             VERSIONFRM,
8655                             message);
8656           }
8657           else
8658           {
8659             xastir_snprintf(temp,
8660                             sizeof(temp),
8661                             "%s>%s,%s:%s",
8662                             my_callsign,
8663                             VERSIONFRM,
8664                             path,
8665                             message);
8666           }
8667         }
8668         else
8669         {
8670           xastir_snprintf(temp,
8671                           sizeof(temp),
8672                           "%s>%s,%s:%s",
8673                           my_callsign,
8674                           VERSIONFRM,
8675                           unproto_path,
8676                           message);
8677         }
8678         makePrintable(temp);
8679         packet_data_add("TX ", temp, port);
8680       }
8681 
8682       if (debug_level & 2)
8683       {
8684         fprintf(stderr,"TX:%d<%s>\n",port,data_txt);
8685       }
8686 
8687       /* add newline on network data */
8688       if (port_data[port].device_type == DEVICE_NET_STREAM)
8689       {
8690         xastir_snprintf(data_txt, sizeof(data_txt), "\n");
8691 
8692         if ( (port_data[port].status == DEVICE_UP)
8693              && (devices[port].transmit_data == 1)
8694              && !transmit_disable
8695              && !loopback_only)
8696         {
8697           port_write_string(port,data_txt);
8698         }
8699       }
8700       else
8701       {
8702       }
8703     }
8704     //        if (incoming_port != -1)
8705     //            port = MAX_IFACE_DEVICES+1;    // process only one port
8706   }
8707 
8708   end_critical_section(&devices_lock, "interface.c:output_my_data" );
8709 
8710   // This will log a posit in the general format for a network interface
8711   // whether or not any network interfaces are currently up.
8712   xastir_snprintf(data_txt, sizeof(data_txt), "%s>%s,TCPIP*:%s", my_callsign,
8713                   VERSIONFRM, message);
8714   if (debug_level & 2)
8715   {
8716     fprintf(stderr,"output_my_data: Transmitting and decoding: %s\n", data_txt);
8717   }
8718 
8719   if (log_net_data)
8720     log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path,
8721                                 sizeof(logfile_tmp_path)),
8722               (char *)data_txt );
8723 
8724 
8725   // Note that this will only log one TNC line per transmission now matter
8726   // how many TNC's are defined.  It's a representative sample of what we're
8727   // sending out.  At least one TNC interface must be enabled in order to
8728   // have anything output to the log file here.
8729   if (data_txt_save[0] != '\0')
8730   {
8731     xastir_snprintf(data_txt, sizeof(data_txt), "%s%s", data_txt_save, message);
8732     if (log_tnc_data)
8733       log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path,
8734                                   sizeof(logfile_tmp_path)),
8735                 (char *)data_txt );
8736   }
8737 
8738 
8739   if (enable_server_port && !loopback_only && !transmit_disable)
8740   {
8741     // Send data to the x_spider server
8742 
8743     if (type == 0)      // My data, add a header
8744     {
8745       xastir_snprintf(data_txt,
8746                       sizeof(data_txt),
8747                       "%s>%s,TCPIP*:%s",
8748                       my_callsign,
8749                       VERSIONFRM,
8750                       message);
8751     }
8752     else    // Not my data, don't add a header
8753     {
8754       xastir_snprintf(data_txt,
8755                       sizeof(data_txt),
8756                       "%s",
8757                       message);
8758     }
8759 
8760     if (writen(pipe_xastir_to_tcp_server,
8761                data_txt,
8762                strlen(data_txt)) != (int)strlen(data_txt))
8763     {
8764       fprintf(stderr,
8765               "output_my_data: Writen error: %d\n",
8766               errno);
8767     }
8768     // Terminate it with a linefeed
8769     if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1)
8770     {
8771       fprintf(stderr,
8772               "output_my_data: Writen error: %d\n",
8773               errno);
8774     }
8775   }
8776   // End of x_spider server send code
8777 
8778 
8779   // Decode our own transmitted packets.
8780   // Note that this function call is destructive to the first parameter.
8781   // This is why we call it _after_ we call the log_data functions.
8782   //
8783   // This must be the "L" packet we see in the View->Messages
8784   // dialog.  We don't see a "T" packet (for TNC) and we only see
8785   // "I" packets if we re-receive our own packet from the internet
8786   // feeds.
8787   if (incoming_port == -1)     // We were sending to all ports
8788   {
8789     // Pretend we received it from port 1
8790     decode_ax25_line( data_txt, DATA_VIA_LOCAL, 1, 1);
8791   }
8792   else    // We were sending to a specific port
8793   {
8794     decode_ax25_line( data_txt, DATA_VIA_LOCAL, incoming_port, 1);
8795   }
8796 }
8797 
8798 
8799 
8800 
8801 
8802 //*****************************************************************************
8803 // output_waypoint_data()
8804 //
8805 // message: the message data to send
8806 //
8807 // This function sends out waypoint creation strings to GPS
8808 // interfaces capable of dealing with it.
8809 //
8810 //*****************************************************************************
output_waypoint_data(char * message)8811 void output_waypoint_data(char *message)
8812 {
8813   char data_txt[MAX_LINE_SIZE+5];
8814   int ok, start, finish, i;
8815 
8816   if (message == NULL)
8817   {
8818     return;
8819   }
8820 
8821   if (message[0] == '\0')
8822   {
8823     return;
8824   }
8825 
8826   if (debug_level & 1)
8827   {
8828     fprintf(stderr,"Sending to GPS interfaces: %s\n", message);
8829   }
8830 
8831   start = 0;
8832   finish = MAX_IFACE_DEVICES;
8833 
8834   begin_critical_section(&devices_lock, "interface.c:output_waypoint_data" );
8835 
8836   for (i = start; i < finish; i++)
8837   {
8838     ok = 1;
8839     switch (port_data[i].device_type)
8840     {
8841 
8842       case DEVICE_SERIAL_TNC_HSP_GPS:
8843         port_dtr(i,1);   // make DTR active (select GPS)
8844         break;
8845 
8846       case DEVICE_SERIAL_GPS:
8847         break;
8848 
8849       default: /* unknown */
8850         ok = 0;
8851         break;
8852     } // End of switch
8853 
8854     if (ok)     // Found a GPS interface
8855     {
8856       /* send data */
8857       xastir_snprintf(data_txt, sizeof(data_txt), "%s\r\n", message);
8858 
8859       if (port_data[i].status == DEVICE_UP)
8860       {
8861         port_write_string(i,data_txt);
8862         usleep(250000);    // 0.25 secs
8863 
8864         if (debug_level & 1)
8865         {
8866           fprintf(stderr,"Sending to interface:%d, %s\n",i,data_txt);
8867         }
8868       }
8869 
8870       if (debug_level & 2)
8871       {
8872         fprintf(stderr,"TX:%d<%s>\n",i,data_txt);
8873       }
8874 
8875       if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS)
8876       {
8877         port_dtr(i,0);  // make DTR inactive (select TNC data)
8878       }
8879     }
8880   }
8881 
8882   end_critical_section(&devices_lock, "interface.c:output_waypoint_data" );
8883 
8884 }
8885 
8886 
8887 
8888 
8889 
8890 // Added by KB6MER for KAM XL(SERIAL_TNC_AUX_GPS) support
8891 // buf is a null terminated string
8892 // returns buf as a null terminated string after cleaning.
8893 // Currently:
8894 //    removes leading 'cmd:' prompts from TNC if needed
8895 // Can be used to add any additional data cleaning functions desired.
8896 // Currently only called for SERIAL_TNC_AUX_GPS, but could be added
8897 // to other device routines to improve packet decode on other devices.
8898 //
8899 // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER,
8900 // which is currently set to 4096.
8901 //
tnc_data_clean(char * buf)8902 void tnc_data_clean(char *buf)
8903 {
8904 
8905   if (debug_level & 1)
8906   {
8907     char filtered_data[MAX_LINE_SIZE+1];
8908 
8909     // strncpy is ok here as long as nulls not in data.  We
8910     // null-terminate it ourselves to make sure it is terminated.
8911     strncpy(filtered_data, buf, MAX_LINE_SIZE);
8912     filtered_data[MAX_LINE_SIZE] = '\0';    // Terminate it
8913 
8914     makePrintable(filtered_data);
8915     fprintf(stderr,"tnc_data_clean: called to clean %s\n", filtered_data);
8916   }
8917 
8918   while (!strncmp(buf,"cmd:",4))
8919   {
8920     int ii;
8921 
8922     // We're _shortening_ the string here, so we don't need to
8923     // know the length of the buffer unless it has no '\0'
8924     // terminator to begin with!  In that one case we could run
8925     // off the end of the string and get a segfault or cause
8926     // other problems.
8927     for (ii = 0; ; ii++)
8928     {
8929       buf[ii] = buf[ii+4];
8930       if (buf[ii] == '\0')
8931       {
8932         break;
8933       }
8934     }
8935   }
8936 
8937   if (debug_level & 1)
8938   {
8939     char filtered_data[MAX_LINE_SIZE+1];
8940 
8941     // Binary routine.  strncpy is ok here as long as nulls not
8942     // in data.  We null-terminate it ourselves to make sure it
8943     // is terminated.
8944     strncpy(filtered_data, buf, MAX_LINE_SIZE);
8945     filtered_data[MAX_LINE_SIZE] = '\0';    // Terminate it
8946 
8947     makePrintable(filtered_data);
8948     fprintf(stderr,"tnc_data_clean: clean result %s\n", filtered_data);
8949   }
8950 }
8951 
8952 
8953 
8954 
8955 
8956 // Added by KB6MER for KAM XL (SERIAL_TNC_AUX_GPS) support
8957 // buf is a null terminated string.
8958 // port is integer offset into port_data[] array of iface data (see interface.h)
8959 // returns int 0=AX25, 1=GPS
8960 // Tries to guess from the contents of buf whether it represents data from
8961 // the GPS or data from an AX25 packet.
8962 //
8963 // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER,
8964 // which is currently set to 4096.
8965 //
tnc_get_data_type(char * buf,int UNUSED (port))8966 int tnc_get_data_type(char *buf, int UNUSED(port) )
8967 {
8968   register int i;
8969   int type=1;      // Don't know what it is yet.  Assume NMEA for now.
8970 
8971   if (debug_level & 1)
8972   {
8973     char filtered_data[MAX_LINE_SIZE+1];
8974 
8975     // Binary routine.  strncpy is ok here as long as nulls not
8976     // in data.  We null-terminate it ourselves to make sure it
8977     // is terminated.
8978     strncpy(filtered_data, buf, MAX_LINE_SIZE);
8979     filtered_data[MAX_LINE_SIZE] = '\0';    // Terminate it
8980 
8981     makePrintable(filtered_data);
8982     fprintf(stderr,"tnc_get_data_type: parsing %s\n", filtered_data);
8983   }
8984 
8985   // First, let's look for NMEA-ish things.
8986   if (buf[0]=='$')
8987   {
8988     //This looks kind of NMEA-ish, let's check for known message type
8989     //headers ($P[A-Z][A-Z][A-Z][A-Z] or $GP[A-Z][A-Z][A-Z])
8990     if(buf[1]=='P')
8991     {
8992       for(i=2; i<=5; i++)
8993       {
8994         if (buf[i]<'A' || buf[i]>'Z')
8995         {
8996           type=0; // Disqualified, not valid NMEA-0183
8997           if (debug_level & 1)
8998           {
8999             char filtered_data[MAX_LINE_SIZE+1];
9000 
9001             // Binary routine.  strncpy is ok here as
9002             // long as nulls not in data.  We
9003             // null-terminate it ourselves to make
9004             // sure it is terminated.
9005             strncpy(filtered_data, buf, MAX_LINE_SIZE);
9006             filtered_data[MAX_LINE_SIZE] = '\0';    // Terminate it
9007 
9008             makePrintable(filtered_data);
9009             fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n",
9010                     filtered_data);
9011           }
9012         }
9013       }
9014     }
9015     else if(buf[1]=='G' && buf[2]=='P')
9016     {
9017       for(i=3; i<=5; i++)
9018       {
9019         if (buf[i]<'A' || buf[i]>'Z')
9020         {
9021           type=0; // Disqualified, not valid NMEA-0183
9022           if (debug_level & 1)
9023           {
9024             char filtered_data[MAX_LINE_SIZE+1];
9025 
9026             // Binary routine.  strncpy is ok here as
9027             // long as nulls not in data.  We
9028             // null-terminate it ourselves to make
9029             // sure it is terminated.
9030             strncpy(filtered_data, buf, MAX_LINE_SIZE);
9031             filtered_data[MAX_LINE_SIZE] = '\0';    // Terminate it
9032 
9033             makePrintable(filtered_data);
9034             fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n",
9035                     filtered_data);
9036           }
9037         }
9038       }
9039     }
9040   }
9041   else    // Must be APRS data
9042   {
9043     type = 0;
9044   }
9045 
9046   if (debug_level & 1)
9047   {
9048     if (type == 0)
9049     {
9050       fprintf(stderr,"APRS data\n");
9051     }
9052     else
9053     {
9054       fprintf(stderr,"NMEA data\n");
9055     }
9056   }
9057 
9058   return(type);
9059 }
9060 
9061 
9062