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