Implement patty_ax25_if_driver
Changes:
    * Implement patty_ax25_if_driver type, providing a vtable with
      pointers to methods implementing an AX.25 interface PHY
    * Implement patty_ax25_if_name() to return a pointer to the name
      string of an AX.25 interface
    * Decouple patty_kiss_tnc from src/if.c using patty_ax25_if_driver
    * Remove port input/output arguments from patty_kiss_tnc_send()
      and patty_kiss_tnc_recv(), respectively; use 0 as the default,
      but keep the port argument in patty_kiss_frame_send()
    * Implement patty_ax25_if_fd() to return file descriptor backing a
      PHY; use this rather than patty_kiss_tnc_fd() in src/server.c to
      further decouple interfaces from their implementation
    * Remove 'enum patty_ax25_if_type' type; refactor constructor
      patty_ax25_if_new() to no longer take this as an argument, but
      rather a patty_ax25_if_driver to use to instantiate the PHY
      with the information pointer passed
    * Break out patty_kiss_tnc code from src/kiss.c into src/tnc.c,
      leaving only patty_kiss_frame_send() in the original; this is
      needed to prevent a cyclic dependency within patty_ax25_sock and
      other areas
    * Rename patty_bin_if_config() to patty_bin_if_create(); a separate
      patty_bin_if_config() will likely be created later as necessary
      to change an existing interface
    * Split PHY-specific interface configuration code into separate
      delegates in bin/if.c
    * Implement usage of patty_error to better capture internal error
      states not currently representable with semantic error numbers
      while configuring and instantiating PHYs
    * Pass patty_error object to patty_bin_kiss_config() to receive
      detailed error information
			
			
This commit is contained in:
		
							parent
							
								
									356b25fd94
								
							
						
					
					
						commit
						cb33d799ff
					
				
					 16 changed files with 669 additions and 586 deletions
				
			
		|  | @ -35,7 +35,7 @@ static void usage(int argc, char **argv, const char *message, ...) { | |||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) { | ||||
|     patty_client *client; | ||||
|     patty_client *client = NULL; | ||||
| 
 | ||||
|     struct option opts[] = { | ||||
|         { NULL, 0, NULL, 0 } | ||||
|  | @ -44,8 +44,7 @@ int main(int argc, char **argv) { | |||
|     uint8_t buf[4096]; | ||||
|     ssize_t readlen; | ||||
| 
 | ||||
|     patty_bin_kiss_data data; | ||||
|     patty_kiss_tnc_info *info = &data.info; | ||||
|     patty_kiss_tnc_info info; | ||||
|     patty_kiss_tnc *raw; | ||||
| 
 | ||||
|     struct stat st; | ||||
|  | @ -66,7 +65,7 @@ int main(int argc, char **argv) { | |||
|         goto error_stat; | ||||
|     } | ||||
| 
 | ||||
|     memset(&data, '\0', sizeof(data)); | ||||
|     memset(&info, '\0', sizeof(info)); | ||||
| 
 | ||||
|     if ((st.st_mode & S_IFMT) == S_IFSOCK) { | ||||
|         patty_client_setsockopt_if ifreq; | ||||
|  | @ -75,7 +74,7 @@ int main(int argc, char **argv) { | |||
|             usage(argc, argv, "No interface name provided"); | ||||
|         } | ||||
| 
 | ||||
|         info->flags = PATTY_KISS_TNC_FD; | ||||
|         info.flags = PATTY_KISS_TNC_FD; | ||||
| 
 | ||||
|         if ((client = patty_client_new(argv[1])) == NULL) { | ||||
|             fprintf(stderr, "%s: %s: %s: %s\n", | ||||
|  | @ -84,7 +83,7 @@ int main(int argc, char **argv) { | |||
|             goto error_client_new; | ||||
|         } | ||||
| 
 | ||||
|         if ((info->fd = patty_client_socket(client, PATTY_AX25_PROTO_NONE, PATTY_AX25_SOCK_RAW)) < 0) { | ||||
|         if ((info.fd = patty_client_socket(client, PATTY_AX25_PROTO_NONE, PATTY_AX25_SOCK_RAW)) < 0) { | ||||
|             fprintf(stderr, "%s: %s: %s\n", | ||||
|                 argv[0], "patty_client_socket()", strerror(errno)); | ||||
| 
 | ||||
|  | @ -95,29 +94,31 @@ int main(int argc, char **argv) { | |||
| 
 | ||||
|         ifreq.state = PATTY_AX25_SOCK_PROMISC; | ||||
| 
 | ||||
|         if (patty_client_setsockopt(client, info->fd, PATTY_AX25_SOCK_IF, &ifreq, sizeof(ifreq)) < 0) { | ||||
|         if (patty_client_setsockopt(client, info.fd, PATTY_AX25_SOCK_IF, &ifreq, sizeof(ifreq)) < 0) { | ||||
|             fprintf(stderr, "%s: %s: %s\n", | ||||
|                 argv[0], "patty_client_setsockopt()", strerror(errno)); | ||||
| 
 | ||||
|             goto error_client_setsockopt; | ||||
|         } | ||||
|     } else { | ||||
|         if (patty_bin_kiss_config(&data, argc - 1, argv + 1) < 0) { | ||||
|         patty_error e; | ||||
| 
 | ||||
|         if (patty_bin_kiss_config(argc - 1, argv + 1, &info, &e) < 0) { | ||||
|             fprintf(stderr, "%s: %s: %s\n", | ||||
|                 argv[0], argv[1], data.err); | ||||
|                 argv[0], argv[1], patty_error_string(&e)); | ||||
| 
 | ||||
|             goto error_kiss_config; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if ((raw = patty_kiss_tnc_new(info)) == NULL) { | ||||
|     if ((raw = patty_kiss_tnc_new(&info)) == NULL) { | ||||
|         fprintf(stderr, "%s: fd %d: %s: %s\n", | ||||
|             argv[0], info->fd, "patty_kiss_tnc_new()", strerror(errno)); | ||||
|             argv[0], info.fd, "patty_kiss_tnc_new()", strerror(errno)); | ||||
| 
 | ||||
|         goto error_kiss_tnc_new; | ||||
|     } | ||||
| 
 | ||||
|     while ((readlen = patty_kiss_tnc_recv(raw, buf, sizeof(buf), NULL)) > 0) { | ||||
|     while ((readlen = patty_kiss_tnc_recv(raw, buf, sizeof(buf))) > 0) { | ||||
|         ssize_t decoded, | ||||
|                 offset = 0; | ||||
| 
 | ||||
|  | @ -178,7 +179,7 @@ error_ax25_frame_decode_address: | |||
|     patty_kiss_tnc_destroy(raw); | ||||
| 
 | ||||
|     if ((st.st_mode & S_IFMT) == S_IFSOCK) { | ||||
|         patty_client_close(client, info->fd); | ||||
|         patty_client_close(client, info.fd); | ||||
| 
 | ||||
|         patty_client_destroy(client); | ||||
|     } | ||||
|  | @ -192,10 +193,10 @@ error_kiss_tnc_new: | |||
| error_kiss_config: | ||||
| error_client_setsockopt: | ||||
| error_client_socket: | ||||
|     if ((st.st_mode & S_IFMT) == S_IFSOCK) patty_client_close(client, info->fd); | ||||
|     if (client) patty_client_close(client, info.fd); | ||||
| 
 | ||||
| error_client_new: | ||||
|     if ((st.st_mode & S_IFMT) == S_IFSOCK) patty_client_destroy(client); | ||||
|     if (client) patty_client_destroy(client); | ||||
| 
 | ||||
| error_stat: | ||||
|     return 1; | ||||
|  |  | |||
							
								
								
									
										195
									
								
								bin/if.c
									
										
									
									
									
								
							
							
						
						
									
										195
									
								
								bin/if.c
									
										
									
									
									
								
							|  | @ -6,6 +6,13 @@ | |||
| 
 | ||||
| #include <patty/bin/if.h> | ||||
| 
 | ||||
| struct context { | ||||
|     patty_error *err; | ||||
| 
 | ||||
|     char *name; | ||||
|     patty_ax25_addr addr; | ||||
| }; | ||||
| 
 | ||||
| enum mode { | ||||
|     MODE_NONE, | ||||
|     MODE_IFNAME, | ||||
|  | @ -16,30 +23,119 @@ enum mode { | |||
|     MODE_FLOW | ||||
| }; | ||||
| 
 | ||||
| static int eprintf(patty_bin_if_data *data, const char *format, ...) { | ||||
|     int ret; | ||||
|     va_list args; | ||||
| static patty_ax25_if *create_kiss(struct context *ctx, int argc, char **argv) { | ||||
|     enum mode mode = MODE_KISS; | ||||
| 
 | ||||
|     va_start(args, format); | ||||
| 
 | ||||
|     ret = vsnprintf(data->err, sizeof(data->err)-1, format, args); | ||||
| 
 | ||||
|     va_end(args); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv) { | ||||
|     enum mode mode = MODE_NONE; | ||||
|     patty_kiss_tnc_info *info = &data->info; | ||||
|     patty_kiss_tnc_info info; | ||||
| 
 | ||||
|     int i; | ||||
| 
 | ||||
|     memset(&info, '\0', sizeof(info)); | ||||
| 
 | ||||
|     if (argc == 0) { | ||||
|         patty_error_fmt(ctx->err, "Too few parameters for 'kiss' interface"); | ||||
| 
 | ||||
|         goto error_invalid; | ||||
|     } | ||||
| 
 | ||||
|     for (i=0; i<argc; i++) { | ||||
|         switch (mode) { | ||||
|             case MODE_KISS: | ||||
|                 info.flags |= PATTY_KISS_TNC_DEVICE; | ||||
|                 info.device = argv[i]; | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_IFOPTS: | ||||
|                 if (strcmp(argv[i], "baud") == 0) { | ||||
|                     mode = MODE_BAUD; | ||||
|                 } else if (strcmp(argv[i], "flow") == 0) { | ||||
|                     mode = MODE_FLOW; | ||||
|                 } else { | ||||
|                     patty_error_fmt(ctx->err, "Invalid parameter '%s'", | ||||
|                         argv[i]); | ||||
|                 } | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_BAUD: | ||||
|                 if (!(argv[i][0] >= '0' && argv[i][0] <= '9')) { | ||||
|                     patty_error_fmt(ctx->err, "Invalid baud rate '%s'", | ||||
|                         argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|                 } | ||||
| 
 | ||||
|                 info.flags |= PATTY_KISS_TNC_BAUD; | ||||
|                 info.baud   = atoi(argv[i]); | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_FLOW: | ||||
|                 if (strcmp(argv[i], "crtscts") == 0) { | ||||
|                     info.flags |= PATTY_KISS_TNC_FLOW; | ||||
|                     info.flow   = PATTY_KISS_TNC_FLOW_CRTSCTS; | ||||
|                 } else if (strcmp(argv[i], "xonxoff") == 0) { | ||||
|                     info.flags |= PATTY_KISS_TNC_FLOW; | ||||
|                     info.flow   = PATTY_KISS_TNC_FLOW_XONXOFF; | ||||
|                 } else { | ||||
|                     patty_error_fmt(ctx->err, "Invalid flow control '%s'", | ||||
|                         argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|                 } | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return patty_ax25_if_new( ctx->name, | ||||
|                              &ctx->addr, | ||||
|                              patty_kiss_tnc_driver(), | ||||
|                              &info); | ||||
| 
 | ||||
| error_invalid: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| struct if_type { | ||||
|     const char *name; | ||||
|     patty_ax25_if *(*func)(struct context *ctx, int argc, char **argv); | ||||
| }; | ||||
| 
 | ||||
| struct if_type if_types[] = { | ||||
|     { "kiss", create_kiss }, | ||||
|     {  NULL,  NULL        } | ||||
| }; | ||||
| 
 | ||||
| patty_ax25_if *patty_bin_if_create(int argc, char **argv, patty_error *e) { | ||||
|     enum mode mode = MODE_NONE; | ||||
| 
 | ||||
|     struct context ctx = { | ||||
|         .err  = e, | ||||
|         .name = NULL | ||||
|     }; | ||||
| 
 | ||||
|     int i; | ||||
| 
 | ||||
|     patty_error_clear(e); | ||||
| 
 | ||||
|     memset(&ctx.addr, '\0', sizeof(ctx.addr)); | ||||
| 
 | ||||
|     for (i=0; i<argc; i++) { | ||||
|         switch (mode) { | ||||
|             case MODE_NONE: | ||||
|                 if (strcmp(argv[i], "if") != 0) { | ||||
|                     eprintf(data, "Unexpected start of expression '%s'", | ||||
|                     patty_error_fmt(e, "Unexpected start of expression '%s'", | ||||
|                         argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|  | @ -50,7 +146,7 @@ int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv) { | |||
|                 break; | ||||
| 
 | ||||
|             case MODE_IFNAME: | ||||
|                 data->name = argv[i]; | ||||
|                 ctx.name = argv[i]; | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|  | @ -59,14 +155,18 @@ int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv) { | |||
|             case MODE_IFOPTS: | ||||
|                 if (strcmp(argv[i], "ax25") == 0) { | ||||
|                     mode = MODE_IFADDR; | ||||
|                 } else if (strcmp(argv[i], "kiss") == 0) { | ||||
|                     mode = MODE_KISS; | ||||
|                 } else if (strcmp(argv[i], "baud") == 0) { | ||||
|                     mode = MODE_BAUD; | ||||
|                 } else if (strcmp(argv[i], "flow") == 0) { | ||||
|                     mode = MODE_FLOW; | ||||
|                 } else { | ||||
|                     eprintf(data, "Invalid parameter '%s'", argv[i]); | ||||
|                     int t; | ||||
| 
 | ||||
|                     for (t=0; if_types[t].name; t++) { | ||||
|                         if (strcmp(if_types[t].name, argv[i]) == 0) { | ||||
|                             return if_types[t].func(&ctx, | ||||
|                                                     argc - i - 1, | ||||
|                                                     argv + i + 1); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     patty_error_fmt(e, "Invalid parameter '%s'", argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|                 } | ||||
|  | @ -74,8 +174,8 @@ int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv) { | |||
|                 break; | ||||
| 
 | ||||
|             case MODE_IFADDR: | ||||
|                 if (patty_ax25_pton(argv[i], &data->addr) < 0) { | ||||
|                     eprintf(data, "Invalid AX.25 address '%s': %s", | ||||
|                 if (patty_ax25_pton(argv[i], &ctx.addr) < 0) { | ||||
|                     patty_error_fmt(e, "Invalid AX.25 address '%s': %s", | ||||
|                         argv[i], strerror(errno)); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|  | @ -85,50 +185,13 @@ int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv) { | |||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_KISS: | ||||
|                 data->type   = PATTY_AX25_IF_KISS_TNC; | ||||
|                 info->flags |= PATTY_KISS_TNC_DEVICE; | ||||
|                 info->device = argv[i]; | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_BAUD: | ||||
|                 if (!(argv[i][0] >= '0' && argv[i][0] <= '9')) { | ||||
|                     eprintf(data, "Invalid baud rate '%s'", argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|                 } | ||||
| 
 | ||||
|                 info->flags |= PATTY_KISS_TNC_BAUD; | ||||
|                 info->baud   = atoi(argv[i]); | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
|             case MODE_FLOW: | ||||
|                 if (strcmp(argv[i], "crtscts") == 0) { | ||||
|                     info->flags |= PATTY_KISS_TNC_FLOW; | ||||
|                     info->flow   = PATTY_KISS_TNC_FLOW_CRTSCTS; | ||||
|                 } else if (strcmp(argv[i], "xonxoff") == 0) { | ||||
|                     info->flags |= PATTY_KISS_TNC_FLOW; | ||||
|                     info->flow   = PATTY_KISS_TNC_FLOW_XONXOFF; | ||||
|                 } else { | ||||
|                     eprintf(data, "Invalid flow control '%s'", argv[i]); | ||||
| 
 | ||||
|                     goto error_invalid; | ||||
|                 } | ||||
| 
 | ||||
|                 mode = MODE_IFOPTS; | ||||
| 
 | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
|     patty_error_fmt(e, "Media type not provided"); | ||||
| 
 | ||||
| error_invalid: | ||||
|     return -1; | ||||
|     return NULL; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										11
									
								
								bin/kiss.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								bin/kiss.c
									
										
									
									
									
								
							|  | @ -4,10 +4,13 @@ | |||
| 
 | ||||
| #include <patty/bin/kiss.h> | ||||
| 
 | ||||
| int patty_bin_kiss_config(patty_bin_kiss_data *data, int argc, char **argv) { | ||||
| int patty_bin_kiss_config(int argc, | ||||
|                           char **argv, | ||||
|                           patty_kiss_tnc_info *info, | ||||
|                           patty_error *e) { | ||||
|     int i; | ||||
| 
 | ||||
|     patty_kiss_tnc_info *info = &data->info; | ||||
|     memset(info, '\0', sizeof(*info)); | ||||
| 
 | ||||
|     info->flags |= PATTY_KISS_TNC_DEVICE; | ||||
|     info->device = argv[0]; | ||||
|  | @ -25,8 +28,8 @@ int patty_bin_kiss_config(patty_bin_kiss_data *data, int argc, char **argv) { | |||
|             info->flags |= PATTY_KISS_TNC_BAUD; | ||||
|             info->baud   = baud; | ||||
|         } else { | ||||
|             snprintf(data->err, sizeof(data->err)-1, | ||||
|                 "Invalid KISS TNC device parameter '%s'", argv[i]); | ||||
|             patty_error_fmt(e, "Invalid KISS TNC device parameter '%s'", | ||||
|                 argv[i]); | ||||
| 
 | ||||
|             goto error_invalid_device_setting; | ||||
|         } | ||||
|  |  | |||
							
								
								
									
										45
									
								
								bin/pattyd.c
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								bin/pattyd.c
									
										
									
									
									
								
							|  | @ -94,10 +94,8 @@ static int handle_if(struct context *ctx, | |||
|                      int lineno, | ||||
|                      int argc, | ||||
|                      char **argv) { | ||||
|     patty_bin_if_data data; | ||||
|     patty_ax25_if *iface; | ||||
| 
 | ||||
|     memset(&data, '\0', sizeof(data)); | ||||
|     patty_error e; | ||||
| 
 | ||||
|     if (argc < 2) { | ||||
|         fprintf(stderr, "%s: line %d: No interface name provided\n", | ||||
|  | @ -111,30 +109,27 @@ static int handle_if(struct context *ctx, | |||
|         goto error_invalid; | ||||
|     } | ||||
| 
 | ||||
|     if (patty_bin_if_config(&data, argc, argv) < 0) { | ||||
|     if ((iface = patty_bin_if_create(argc, argv, &e)) == NULL) { | ||||
|         fprintf(stderr, "%s: line %d: %s\n", | ||||
|             ctx->config_file, lineno, data.err); | ||||
|             ctx->config_file, lineno, patty_error_string(&e)); | ||||
| 
 | ||||
|         goto error_invalid; | ||||
|     } | ||||
| 
 | ||||
|     if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC, | ||||
|                                     data.name, | ||||
|                                    &data.info, | ||||
|                                    &data.addr)) == NULL) { | ||||
|         goto error_if_new; | ||||
|     } else { | ||||
|         int fd = patty_kiss_tnc_fd(iface->tnc); | ||||
|         int fd = patty_ax25_if_fd(iface); | ||||
|         char *pty; | ||||
| 
 | ||||
|         if (isatty(fd) && (pty = ptsname(fd)) != NULL) { | ||||
|             printf("if %s pty %s\n", data.name, pty); | ||||
|             printf("if %s pty %s\n", | ||||
|                 patty_ax25_if_name(iface), pty); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (patty_daemon_if_add(ctx->daemon, iface) < 0) { | ||||
|         fprintf(stderr, "%s: line %d: Unable to create interface %s: %s\n", | ||||
|             ctx->config_file, lineno, data.name, strerror(errno)); | ||||
|             ctx->config_file, | ||||
|             lineno, | ||||
|             patty_ax25_if_name(iface), | ||||
|             strerror(errno)); | ||||
| 
 | ||||
|         goto error_daemon_if_add; | ||||
|     } | ||||
|  | @ -144,7 +139,6 @@ static int handle_if(struct context *ctx, | |||
| error_daemon_if_add: | ||||
|     patty_ax25_if_destroy(iface); | ||||
| 
 | ||||
| error_if_new: | ||||
| error_invalid: | ||||
|     return -1; | ||||
| } | ||||
|  | @ -281,9 +275,8 @@ static int handle_standalone(patty_daemon *daemon, | |||
|     patty_ax25_if *iface; | ||||
|     patty_ax25_addr addr; | ||||
| 
 | ||||
|     patty_bin_kiss_data data; | ||||
| 
 | ||||
|     memset(&data, '\0', sizeof(data)); | ||||
|     patty_kiss_tnc_info info; | ||||
|     patty_error e; | ||||
| 
 | ||||
|     if (patty_daemon_set_sock_path(daemon, argv[0]) < 0) { | ||||
|         fprintf(stderr, "%s: Unable to set socket path to %s: %s\n", | ||||
|  | @ -299,23 +292,23 @@ static int handle_standalone(patty_daemon *daemon, | |||
|         goto error_invalid_callsign; | ||||
|     } | ||||
| 
 | ||||
|     if (patty_bin_kiss_config(&data, argc - 2, argv + 2) < 0) { | ||||
|     if (patty_bin_kiss_config(argc - 2, argv + 2, &info, &e) < 0) { | ||||
|         fprintf(stderr, "%s: %s: %s\n", | ||||
|             argv0, argv[2], data.err); | ||||
|             argv0, argv[2], patty_error_string(&e)); | ||||
| 
 | ||||
|         goto error_kiss_config; | ||||
|     } | ||||
| 
 | ||||
|     if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC, | ||||
|                                    DEFAULT_IFNAME, | ||||
|                                    &data.info, | ||||
|                                    &addr)) == NULL) { | ||||
|     if ((iface = patty_ax25_if_new(DEFAULT_IFNAME, | ||||
|                                    &addr, | ||||
|                                    patty_kiss_tnc_driver(), | ||||
|                                    &info)) == NULL) { | ||||
|         fprintf(stderr, "%s: Unable to create network interface %s: %s\n", | ||||
|             argv0, DEFAULT_IFNAME, strerror(errno)); | ||||
| 
 | ||||
|         goto error_if_new; | ||||
|     } else { | ||||
|         int fd = patty_kiss_tnc_fd(iface->tnc); | ||||
|         int fd = patty_ax25_if_fd(iface); | ||||
|         char *pty; | ||||
| 
 | ||||
|         if (isatty(fd) && (pty = ptsname(fd)) != NULL) { | ||||
|  |  | |||
|  | @ -5,7 +5,6 @@ | |||
| #include <sys/types.h> | ||||
| #include <sys/time.h> | ||||
| 
 | ||||
| #include <patty/kiss.h> | ||||
| #include <patty/list.h> | ||||
| #include <patty/dict.h> | ||||
| 
 | ||||
|  | @ -104,6 +103,7 @@ typedef struct _patty_ax25_if patty_ax25_if; | |||
| #include <patty/client.h> | ||||
| #include <patty/ax25/frame.h> | ||||
| #include <patty/ax25/if.h> | ||||
| #include <patty/kiss/tnc.h> | ||||
| #include <patty/ax25/route.h> | ||||
| #include <patty/ax25/sock.h> | ||||
| #include <patty/ax25/server.h> | ||||
|  |  | |||
|  | @ -12,12 +12,6 @@ | |||
| #define PATTY_AX25_IF_DEFAULT_MTU 4096 | ||||
| #define PATTY_AX25_IF_DEFAULT_MRU 4096 | ||||
| 
 | ||||
| enum patty_ax25_if_type { | ||||
|     PATTY_AX25_IF_UNKNOWN, | ||||
|     PATTY_AX25_IF_KISS_TNC, | ||||
|     PATTY_AX25_IF_HDLC | ||||
| }; | ||||
| 
 | ||||
| enum patty_ax25_if_flags { | ||||
|     PATTY_AX25_IF_HALF_DUPLEX = (1 << 0), | ||||
|     PATTY_AX25_IF_FULL_DUPLEX = (1 << 1), | ||||
|  | @ -33,9 +27,33 @@ typedef struct _patty_ax25_if_stats { | |||
|            dropped; | ||||
| } patty_ax25_if_stats; | ||||
| 
 | ||||
| typedef void *(patty_ax25_if_driver_create)(void *); | ||||
| 
 | ||||
| typedef void (patty_ax25_if_driver_destroy)(void *); | ||||
| 
 | ||||
| typedef int (patty_ax25_if_driver_fd)(void *); | ||||
| 
 | ||||
| typedef int (patty_ax25_if_driver_pending)(void *); | ||||
| 
 | ||||
| typedef ssize_t (patty_ax25_if_driver_recv)(void *, void *, size_t); | ||||
| 
 | ||||
| typedef ssize_t (patty_ax25_if_driver_send)(void *, const void *, size_t); | ||||
| 
 | ||||
| typedef struct _patty_ax25_if_driver { | ||||
|     patty_ax25_if_driver_create *create; | ||||
|     patty_ax25_if_driver_destroy *destroy; | ||||
|     patty_ax25_if_driver_fd *fd; | ||||
|     patty_ax25_if_driver_pending *pending; | ||||
|     patty_ax25_if_driver_recv *recv; | ||||
|     patty_ax25_if_driver_send *send; | ||||
| } patty_ax25_if_driver; | ||||
| 
 | ||||
| typedef void patty_ax25_if_phy; | ||||
| 
 | ||||
| typedef void patty_ax25_if_info; | ||||
| 
 | ||||
| typedef struct _patty_ax25_if { | ||||
|     enum patty_ax25_if_type  type; | ||||
|          patty_ax25_if_stats stats; | ||||
|     patty_ax25_if_stats stats; | ||||
| 
 | ||||
|     char name[8]; | ||||
| 
 | ||||
|  | @ -47,21 +65,23 @@ typedef struct _patty_ax25_if { | |||
|     size_t mru, | ||||
|            mtu; | ||||
| 
 | ||||
|     patty_kiss_tnc *tnc; | ||||
|     patty_ax25_addr addr; | ||||
|     patty_list *aliases; | ||||
|     patty_dict *promisc_fds; | ||||
| 
 | ||||
|     patty_ax25_if_driver *driver; | ||||
|     patty_ax25_if_phy *phy; | ||||
| } patty_ax25_if; | ||||
| 
 | ||||
| typedef void patty_ax25_if_info; | ||||
| 
 | ||||
| patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type, | ||||
|                                  const char *name, | ||||
|                                  patty_ax25_if_info *info, | ||||
|                                  patty_ax25_addr *addr); | ||||
| patty_ax25_if *patty_ax25_if_new(const char *name, | ||||
|                                  patty_ax25_addr *addr, | ||||
|                                  patty_ax25_if_driver *driver, | ||||
|                                  patty_ax25_if_info *info); | ||||
| 
 | ||||
| void patty_ax25_if_destroy(patty_ax25_if *iface); | ||||
| 
 | ||||
| char *patty_ax25_if_name(patty_ax25_if *iface); | ||||
| 
 | ||||
| int patty_ax25_if_addr_each(patty_ax25_if *iface, | ||||
|                             int (*callback)(patty_ax25_addr *, void *), | ||||
|                             void *ctx); | ||||
|  | @ -78,6 +98,8 @@ int patty_ax25_if_promisc_add(patty_ax25_if *iface, | |||
| int patty_ax25_if_promisc_delete(patty_ax25_if *iface, | ||||
|                                  int fd); | ||||
| 
 | ||||
| int patty_ax25_if_fd(patty_ax25_if *iface); | ||||
| 
 | ||||
| ssize_t patty_ax25_if_pending(patty_ax25_if *iface); | ||||
| 
 | ||||
| ssize_t patty_ax25_if_recv(patty_ax25_if *iface, | ||||
|  |  | |||
|  | @ -123,7 +123,7 @@ typedef struct _patty_ax25_sock { | |||
|     /*
 | ||||
|      * Reader for raw packets for PATTY_AX25_SOCK_RAW type | ||||
|      */ | ||||
|     patty_kiss_tnc *raw; | ||||
|     struct _patty_kiss_tnc *raw; | ||||
| 
 | ||||
|     /*
 | ||||
|      * File descriptor information | ||||
|  |  | |||
|  | @ -2,16 +2,10 @@ | |||
| #define _PATTY_BIN_IF_H | ||||
| 
 | ||||
| #include <patty/ax25.h> | ||||
| #include <patty/error.h> | ||||
| 
 | ||||
| typedef struct _patty_bin_if_data { | ||||
|     char *name; | ||||
|     char err[256]; | ||||
| 
 | ||||
|     enum patty_ax25_if_type  type; | ||||
|          patty_ax25_addr     addr; | ||||
|          patty_kiss_tnc_info info; | ||||
| } patty_bin_if_data; | ||||
| 
 | ||||
| int patty_bin_if_config(patty_bin_if_data *data, int argc, char **argv); | ||||
| patty_ax25_if *patty_bin_if_create(int argc, | ||||
|                                    char **argv, | ||||
|                                    patty_error *e); | ||||
| 
 | ||||
| #endif /* _PATTY_BIN_IF_H */ | ||||
|  |  | |||
|  | @ -1,13 +1,13 @@ | |||
| #ifndef _PATTY_BIN_KISS_H | ||||
| #define _PATTY_BIN_KISS_H | ||||
| 
 | ||||
| #include <patty/kiss.h> | ||||
| #include <patty/error.h> | ||||
| 
 | ||||
| typedef struct _patty_bin_kiss_data { | ||||
|     char err[256]; | ||||
|     patty_kiss_tnc_info info; | ||||
| } patty_bin_kiss_data; | ||||
| #include <patty/kiss/tnc.h> | ||||
| 
 | ||||
| int patty_bin_kiss_config(patty_bin_kiss_data *data, int argc, char **argv); | ||||
| int patty_bin_kiss_config(int argc, | ||||
|                           char **argv, | ||||
|                           patty_kiss_tnc_info *info, | ||||
|                           patty_error *e); | ||||
| 
 | ||||
| #endif /* _PATTY_BIN_KISS_H */ | ||||
|  |  | |||
|  | @ -2,17 +2,14 @@ | |||
| #define _PATTY_KISS_H | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <termios.h> | ||||
| 
 | ||||
| #define PATTY_KISS_FEND  0xc0 | ||||
| #define PATTY_KISS_FESC  0xdb | ||||
| #define PATTY_KISS_TFEND 0xdc | ||||
| #define PATTY_KISS_TFESC 0xdd | ||||
| 
 | ||||
| #define PATTY_KISS_BUFSZ 4096 | ||||
| 
 | ||||
| #define PATTY_KISS_COMMAND(cmd) \ | ||||
|     (cmd & 0x0f) | ||||
|     ((cmd & 0x0f)) | ||||
| 
 | ||||
| #define PATTY_KISS_COMMAND_PORT(cmd) \ | ||||
|     ((cmd & 0xf0) >> 4) | ||||
|  | @ -33,46 +30,4 @@ ssize_t patty_kiss_frame_send(int fd, | |||
|                               size_t len, | ||||
|                               int port); | ||||
| 
 | ||||
| typedef struct _patty_kiss_tnc patty_kiss_tnc; | ||||
| 
 | ||||
| #define PATTY_KISS_TNC_DEVICE (1 << 0) | ||||
| #define PATTY_KISS_TNC_FD     (1 << 1) | ||||
| #define PATTY_KISS_TNC_BAUD   (1 << 2) | ||||
| #define PATTY_KISS_TNC_FLOW   (1 << 3) | ||||
| 
 | ||||
| enum patty_kiss_tnc_flow { | ||||
|     PATTY_KISS_TNC_FLOW_NONE, | ||||
|     PATTY_KISS_TNC_FLOW_CRTSCTS, | ||||
|     PATTY_KISS_TNC_FLOW_XONXOFF | ||||
| }; | ||||
| 
 | ||||
| typedef struct _patty_kiss_tnc_info { | ||||
|     int flags; | ||||
| 
 | ||||
|     const char *device; | ||||
|     int fd; | ||||
|     speed_t baud; | ||||
|     enum patty_kiss_tnc_flow flow; | ||||
| } patty_kiss_tnc_info; | ||||
| 
 | ||||
| patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info); | ||||
| 
 | ||||
| int patty_kiss_tnc_fd(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, | ||||
|                             void *buf, | ||||
|                             size_t len, | ||||
|                             int *port); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, | ||||
|                             const void *buf, | ||||
|                             size_t len, | ||||
|                             int port); | ||||
| 
 | ||||
| #endif /* _PATTY_KISS_H */ | ||||
|  |  | |||
							
								
								
									
										54
									
								
								include/patty/kiss/tnc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								include/patty/kiss/tnc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| #ifndef _PATTY_KISS_TNC_H | ||||
| #define _PATTY_KISS_TNC_H | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <termios.h> | ||||
| 
 | ||||
| #include <patty/ax25.h> | ||||
| 
 | ||||
| #define PATTY_KISS_TNC_BUFSZ 4096 | ||||
| #define PATTY_KISS_TNC_PORT     0 | ||||
| 
 | ||||
| typedef struct _patty_kiss_tnc patty_kiss_tnc; | ||||
| 
 | ||||
| #define PATTY_KISS_TNC_DEVICE (1 << 0) | ||||
| #define PATTY_KISS_TNC_FD     (1 << 1) | ||||
| #define PATTY_KISS_TNC_BAUD   (1 << 2) | ||||
| #define PATTY_KISS_TNC_FLOW   (1 << 3) | ||||
| 
 | ||||
| enum patty_kiss_tnc_flow { | ||||
|     PATTY_KISS_TNC_FLOW_NONE, | ||||
|     PATTY_KISS_TNC_FLOW_CRTSCTS, | ||||
|     PATTY_KISS_TNC_FLOW_XONXOFF | ||||
| }; | ||||
| 
 | ||||
| typedef struct _patty_kiss_tnc_info { | ||||
|     int flags; | ||||
| 
 | ||||
|     const char *device; | ||||
|     int fd; | ||||
|     speed_t baud; | ||||
|     enum patty_kiss_tnc_flow flow; | ||||
| } patty_kiss_tnc_info; | ||||
| 
 | ||||
| patty_ax25_if_driver *patty_kiss_tnc_driver(); | ||||
| 
 | ||||
| patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info); | ||||
| 
 | ||||
| int patty_kiss_tnc_fd(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, | ||||
|                             void *buf, | ||||
|                             size_t len); | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, | ||||
|                             const void *buf, | ||||
|                             size_t len); | ||||
| 
 | ||||
| #endif /* _PATTY_KISS_H */ | ||||
							
								
								
									
										106
									
								
								src/if.c
									
										
									
									
									
								
							
							
						
						
									
										106
									
								
								src/if.c
									
										
									
									
									
								
							|  | @ -5,46 +5,36 @@ | |||
| #include <errno.h> | ||||
| 
 | ||||
| #include <patty/ax25.h> | ||||
| #include <patty/kiss.h> | ||||
| 
 | ||||
| static int init_tnc(patty_ax25_if *iface, patty_kiss_tnc_info *info) { | ||||
|     if ((iface->tnc = patty_kiss_tnc_new(info)) == NULL) { | ||||
|         goto error_kiss_tnc_new; | ||||
|     } | ||||
| 
 | ||||
|     iface->type = PATTY_AX25_IF_KISS_TNC; | ||||
| 
 | ||||
|     return 0; | ||||
| 
 | ||||
| error_kiss_tnc_new: | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| static void destroy_tnc(patty_ax25_if *iface) { | ||||
|     patty_kiss_tnc_destroy(iface->tnc); | ||||
| } | ||||
| 
 | ||||
| patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type, | ||||
|                                  const char *name, | ||||
|                                  patty_ax25_if_info *info, | ||||
|                                  patty_ax25_addr *addr) { | ||||
| patty_ax25_if *patty_ax25_if_new(const char *name, | ||||
|                                  patty_ax25_addr *addr, | ||||
|                                  patty_ax25_if_driver *driver, | ||||
|                                  patty_ax25_if_info *info) { | ||||
|     patty_ax25_if *iface; | ||||
| 
 | ||||
|     if ((iface = malloc(sizeof(*iface))) == NULL) { | ||||
|         goto error_malloc_iface; | ||||
|     } | ||||
| 
 | ||||
|     memset(iface, '\0', sizeof(*iface)); | ||||
| 
 | ||||
|     strncpy(iface->name, name, sizeof(iface->name)); | ||||
| 
 | ||||
|     if (addr->callsign[0] == '\0') { | ||||
|         errno = EINVAL; | ||||
| 
 | ||||
|         goto error_invalid_address; | ||||
|     } | ||||
| 
 | ||||
|     if ((iface = malloc(sizeof(*iface))) == NULL) { | ||||
|         goto error_malloc_iface; | ||||
|     } | ||||
| 
 | ||||
|     memset(iface, '\0', sizeof(*iface)); | ||||
| 
 | ||||
|     if ((iface->phy = driver->create(info)) == NULL) { | ||||
|         goto error_phy_create; | ||||
|     } | ||||
| 
 | ||||
|     iface->driver = driver; | ||||
| 
 | ||||
|     strncpy(iface->name, name, sizeof(iface->name)); | ||||
| 
 | ||||
|     /*
 | ||||
|      * TODO: Eventually inherit the half/full-duplex flag from the TNC this | ||||
|      * TODO: Eventually inherit the half/full-duplex flag from the PHY this | ||||
|      * interface is bound to | ||||
|      */ | ||||
|     iface->flags_classes = PATTY_AX25_IF_DEFAULT_CLASSES; | ||||
|  | @ -69,28 +59,10 @@ patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type, | |||
|         goto error_dict_new_promisc_fds; | ||||
|     } | ||||
| 
 | ||||
|     switch (type) { | ||||
|         case PATTY_AX25_IF_KISS_TNC: | ||||
|             if (init_tnc(iface, info) < 0) { | ||||
|                 goto error_init; | ||||
|             } | ||||
|              | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             errno = ENOSYS; | ||||
| 
 | ||||
|             goto error_invalid_if_type; | ||||
|     } | ||||
| 
 | ||||
|     memcpy(&iface->addr, addr, sizeof(iface->addr)); | ||||
| 
 | ||||
|     return iface; | ||||
| 
 | ||||
| error_invalid_if_type: | ||||
| error_init: | ||||
|     patty_dict_destroy(iface->promisc_fds); | ||||
| 
 | ||||
| error_dict_new_promisc_fds: | ||||
|     patty_list_destroy(iface->aliases); | ||||
| 
 | ||||
|  | @ -101,6 +73,9 @@ error_malloc_tx_buf: | |||
|     free(iface->rx_buf); | ||||
| 
 | ||||
| error_malloc_rx_buf: | ||||
|     driver->destroy(iface->phy); | ||||
| 
 | ||||
| error_phy_create: | ||||
|     free(iface); | ||||
| 
 | ||||
| error_malloc_iface: | ||||
|  | @ -109,13 +84,8 @@ error_invalid_address: | |||
| } | ||||
| 
 | ||||
| void patty_ax25_if_destroy(patty_ax25_if *iface) { | ||||
|     switch (iface->type) { | ||||
|         case PATTY_AX25_IF_KISS_TNC: | ||||
|             destroy_tnc(iface); | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             break; | ||||
|     if (iface->driver->destroy) { | ||||
|         iface->driver->destroy(iface->phy); | ||||
|     } | ||||
| 
 | ||||
|     patty_dict_destroy(iface->promisc_fds); | ||||
|  | @ -126,6 +96,10 @@ void patty_ax25_if_destroy(patty_ax25_if *iface) { | |||
|     free(iface); | ||||
| } | ||||
| 
 | ||||
| char *patty_ax25_if_name(patty_ax25_if *iface) { | ||||
|     return iface->name; | ||||
| } | ||||
| 
 | ||||
| int patty_ax25_if_addr_each(patty_ax25_if *iface, | ||||
|                             int (*callback)(patty_ax25_addr *, void *), | ||||
|                             void *ctx) { | ||||
|  | @ -297,21 +271,23 @@ static int handle_promisc_frame(uint32_t key, | |||
|     return patty_kiss_frame_send(fd, frame->buf, frame->len, 0); | ||||
| } | ||||
| 
 | ||||
| int patty_ax25_if_fd(patty_ax25_if *iface) { | ||||
|     return iface->driver->fd(iface->phy); | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_ax25_if_pending(patty_ax25_if *iface) { | ||||
|     return patty_kiss_tnc_pending(iface->tnc); | ||||
|     return iface->driver->pending(iface->phy); | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_ax25_if_recv(patty_ax25_if *iface, | ||||
|                            void **buf) { | ||||
|     ssize_t readlen; | ||||
|     int port; | ||||
|     struct promisc_frame frame; | ||||
| 
 | ||||
|     if ((readlen = patty_kiss_tnc_recv(iface->tnc, | ||||
|     if ((readlen = iface->driver->recv(iface->phy, | ||||
|                                        iface->rx_buf, | ||||
|                                        iface->mru, | ||||
|                                        &port)) < 0) { | ||||
|         goto error_kiss_tnc_recv; | ||||
|                                        iface->mru)) < 0) { | ||||
|         goto error_driver_recv; | ||||
|     } else if (readlen == 0) { | ||||
|         goto done; | ||||
|     } | ||||
|  | @ -335,7 +311,7 @@ done: | |||
|     return readlen; | ||||
| 
 | ||||
| error_handle_promisc_frame: | ||||
| error_kiss_tnc_recv: | ||||
| error_driver_recv: | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
|  | @ -345,8 +321,8 @@ ssize_t patty_ax25_if_send(patty_ax25_if *iface, | |||
|     ssize_t wrlen; | ||||
|     struct promisc_frame frame; | ||||
| 
 | ||||
|     if ((wrlen = patty_kiss_tnc_send(iface->tnc, buf, len, 0)) < 0) { | ||||
|         goto error_kiss_tnc_send; | ||||
|     if ((wrlen = iface->driver->send(iface->phy, buf, len)) < 0) { | ||||
|         goto error_driver_send; | ||||
|     } | ||||
| 
 | ||||
|     iface->stats.tx_frames++; | ||||
|  | @ -365,6 +341,6 @@ ssize_t patty_ax25_if_send(patty_ax25_if *iface, | |||
|     return wrlen; | ||||
| 
 | ||||
| error_handle_promisc_frame: | ||||
| error_kiss_tnc_send: | ||||
| error_driver_send: | ||||
|     return -1; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										325
									
								
								src/kiss.c
									
										
									
									
									
								
							
							
						
						
									
										325
									
								
								src/kiss.c
									
										
									
									
									
								
							|  | @ -15,35 +15,6 @@ | |||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| enum kiss_flags { | ||||
|     KISS_NONE    = 0, | ||||
|     KISS_FRAME   = 1 << 0, | ||||
|     KISS_COMMAND = 1 << 1, | ||||
|     KISS_ESCAPE  = 1 << 2 | ||||
| }; | ||||
| 
 | ||||
| enum tnc_opts { | ||||
|     TNC_NONE             = 0, | ||||
|     TNC_CLOSE_ON_DESTROY = 1 << 0 | ||||
| }; | ||||
| 
 | ||||
| struct _patty_kiss_tnc { | ||||
|     struct termios attrs, | ||||
|                    attrs_old; | ||||
| 
 | ||||
|     int fd, | ||||
|         opts; | ||||
| 
 | ||||
|     void *buf, | ||||
|          *frame; | ||||
| 
 | ||||
|     size_t bufsz, | ||||
|            offset, | ||||
|            dropped; | ||||
| 
 | ||||
|     ssize_t readlen; | ||||
| }; | ||||
| 
 | ||||
| static inline ssize_t write_byte(int fd, uint8_t c) { | ||||
|     return write(fd, &c, sizeof(c)); | ||||
| } | ||||
|  | @ -121,299 +92,3 @@ ssize_t patty_kiss_frame_send(int fd, | |||
| error_io: | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { | ||||
|     patty_kiss_tnc *tnc; | ||||
| 
 | ||||
|     if ((tnc = malloc(sizeof(*tnc))) == NULL) { | ||||
|         goto error_malloc_tnc; | ||||
|     } | ||||
| 
 | ||||
|     if ((tnc->buf = malloc(PATTY_KISS_BUFSZ)) == NULL) { | ||||
|         goto error_malloc_buf; | ||||
|     } | ||||
| 
 | ||||
|     if (info->flags & PATTY_KISS_TNC_DEVICE) { | ||||
|         struct stat st; | ||||
| 
 | ||||
|         if (strcmp(info->device, "/dev/ptmx") == 0) { | ||||
|             int ptysub; | ||||
| 
 | ||||
|             if (openpty(&tnc->fd, &ptysub, NULL, NULL, NULL) < 0) { | ||||
|                 goto error_open; | ||||
|             } | ||||
|         } else if (stat(info->device, &st) < 0) { | ||||
|             goto error_stat; | ||||
|         } else if ((st.st_mode & S_IFMT) == S_IFSOCK) { | ||||
|             struct sockaddr_un addr; | ||||
| 
 | ||||
|             if (strlen(info->device) > sizeof(addr.sun_path)) { | ||||
|                 errno = EOVERFLOW; | ||||
| 
 | ||||
|                 goto error_overflow; | ||||
|             } | ||||
| 
 | ||||
|             if ((tnc->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
|                 goto error_socket; | ||||
|             } | ||||
| 
 | ||||
|             memset(&addr, '\0', sizeof(addr)); | ||||
|             addr.sun_family = AF_UNIX; | ||||
|             strncpy(addr.sun_path, info->device, sizeof(addr.sun_path)-1); | ||||
| 
 | ||||
|             if (connect(tnc->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||||
|                 goto error_connect; | ||||
|             } | ||||
|         } else { | ||||
|             if ((tnc->fd = open(info->device, O_RDWR | O_NOCTTY)) < 0) { | ||||
|                 goto error_open; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tnc->opts |= TNC_CLOSE_ON_DESTROY; | ||||
|     } else if (info->flags & PATTY_KISS_TNC_FD) { | ||||
|         tnc->fd = info->fd; | ||||
|     } else { | ||||
|         errno = EINVAL; | ||||
| 
 | ||||
|         goto error_no_fd; | ||||
|     } | ||||
| 
 | ||||
|     if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) { | ||||
|         if (tcgetattr(tnc->fd, &tnc->attrs) < 0) { | ||||
|             goto error_tcgetattr; | ||||
|         } | ||||
| 
 | ||||
|         memcpy(&tnc->attrs_old, &tnc->attrs, sizeof(tnc->attrs_old)); | ||||
| 
 | ||||
|         cfmakeraw(&tnc->attrs); | ||||
| 
 | ||||
|         if (info->flags & PATTY_KISS_TNC_BAUD) { | ||||
|             cfsetspeed(&tnc->attrs, info->baud); | ||||
|         } | ||||
| 
 | ||||
|         if (info->flags & PATTY_KISS_TNC_FLOW) { | ||||
|             switch (info->flow) { | ||||
|                 case PATTY_KISS_TNC_FLOW_NONE: | ||||
|                     break; | ||||
| 
 | ||||
|                 case PATTY_KISS_TNC_FLOW_CRTSCTS: | ||||
|                     tnc->attrs.c_cflag |= CRTSCTS; | ||||
| 
 | ||||
|                     break; | ||||
| 
 | ||||
|                 case PATTY_KISS_TNC_FLOW_XONXOFF: | ||||
|                     tnc->attrs.c_iflag |= IXON | IXOFF; | ||||
| 
 | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (tcflush(tnc->fd, TCIOFLUSH) < 0) { | ||||
|             goto error_tcflush; | ||||
|         } | ||||
| 
 | ||||
|         if (tcsetattr(tnc->fd, TCSANOW, &tnc->attrs) < 0) { | ||||
|             goto error_tcsetattr; | ||||
|         } | ||||
|     } else { | ||||
|         errno = 0; | ||||
|     } | ||||
| 
 | ||||
|     tnc->opts    =  TNC_NONE; | ||||
|     tnc->bufsz   =  PATTY_KISS_BUFSZ; | ||||
|     tnc->offset  =  0; | ||||
|     tnc->dropped =  0; | ||||
|     tnc->readlen = -1; | ||||
| 
 | ||||
|     return tnc; | ||||
| 
 | ||||
| error_tcflush: | ||||
| error_tcsetattr: | ||||
| error_tcgetattr: | ||||
| error_connect: | ||||
|     if (info->flags & PATTY_KISS_TNC_DEVICE) { | ||||
|         (void)close(tnc->fd); | ||||
|     } | ||||
| 
 | ||||
| error_open: | ||||
| error_no_fd: | ||||
| error_socket: | ||||
| error_overflow: | ||||
| error_stat: | ||||
|     free(tnc->buf); | ||||
| 
 | ||||
| error_malloc_buf: | ||||
|     free(tnc); | ||||
| 
 | ||||
| error_malloc_tnc: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) { | ||||
|     return tnc->fd; | ||||
| } | ||||
| 
 | ||||
| void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc) { | ||||
|     if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) { | ||||
|         (void)tcsetattr(tnc->fd, TCSANOW, &tnc->attrs_old); | ||||
|     } | ||||
| 
 | ||||
|     if (tnc->opts & TNC_CLOSE_ON_DESTROY) { | ||||
|         (void)close(tnc->fd); | ||||
|     } | ||||
| 
 | ||||
|     free(tnc->buf); | ||||
|     free(tnc); | ||||
| } | ||||
| 
 | ||||
| static void tnc_drop(patty_kiss_tnc *tnc) { | ||||
|     tnc->offset  =  0; | ||||
|     tnc->readlen = -1; | ||||
|     tnc->dropped++; | ||||
| } | ||||
| 
 | ||||
| size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) { | ||||
|     return tnc->dropped; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc) { | ||||
|     if (tnc->readlen < 0) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (tnc->offset == 0) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return tnc->readlen - tnc->offset; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, | ||||
|                             void *buf, | ||||
|                             size_t len, | ||||
|                             int *port) { | ||||
|     size_t r = 0, /* Number of bytes read */ | ||||
|            w = 0; /* Number of bytes written to buf */ | ||||
| 
 | ||||
|     int flags = KISS_NONE; | ||||
| 
 | ||||
|     if (tnc->offset == tnc->readlen) { | ||||
|         errno = 0; | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     while (1) { | ||||
|         uint8_t c; | ||||
| 
 | ||||
|         r++; | ||||
| 
 | ||||
|         if (w == len) { | ||||
|             tnc_drop(tnc); | ||||
| 
 | ||||
|             flags &= ~KISS_FRAME; | ||||
|                 w  = 0; | ||||
|         } | ||||
| 
 | ||||
|         if (tnc->offset == 0) { | ||||
|             if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) { | ||||
|                 goto error_io; | ||||
|             } else if (tnc->readlen == 0) { | ||||
|                 goto done; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         c = ((uint8_t *)tnc->buf)[tnc->offset++]; | ||||
| 
 | ||||
|         if (tnc->offset == tnc->readlen) { | ||||
|             tnc->offset = 0; | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & KISS_FRAME)) { | ||||
|             if (c == PATTY_KISS_FEND) { | ||||
|                 flags = KISS_FRAME; | ||||
| 
 | ||||
|                 continue; | ||||
|             } else { | ||||
|                 errno = EIO; | ||||
| 
 | ||||
|                 goto error_io; | ||||
|             } | ||||
|         } else { | ||||
|             if (c == PATTY_KISS_FEND) { | ||||
|                 flags = KISS_NONE; | ||||
| 
 | ||||
|                 if (w > 0) { | ||||
|                     goto done; | ||||
|                 } | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & KISS_COMMAND)) { | ||||
|             if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { | ||||
|                 errno = EIO; | ||||
| 
 | ||||
|                 goto error_io; | ||||
|             } | ||||
| 
 | ||||
|             if (port) { | ||||
|                 *port = PATTY_KISS_COMMAND_PORT(c); | ||||
|             } | ||||
| 
 | ||||
|             flags |= KISS_COMMAND; | ||||
| 
 | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & KISS_ESCAPE)) { | ||||
|             if (c == PATTY_KISS_FESC) { | ||||
|                 flags |= KISS_ESCAPE; | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
|         } else { | ||||
|             switch (c) { | ||||
|                 case PATTY_KISS_TFEND: | ||||
|                     ((uint8_t *)buf)[w++] = PATTY_KISS_FEND; | ||||
|                     flags &= ~KISS_ESCAPE; | ||||
|                     continue; | ||||
| 
 | ||||
|                 case PATTY_KISS_TFESC: | ||||
|                     ((uint8_t *)buf)[w++] = PATTY_KISS_FESC; | ||||
|                     flags &= ~KISS_ESCAPE; | ||||
|                     continue; | ||||
| 
 | ||||
|                 default: | ||||
|                     errno = EIO; | ||||
| 
 | ||||
|                     goto error_io; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ((uint8_t *)buf)[w++] = c; | ||||
|     } | ||||
| 
 | ||||
| done: | ||||
|     if (flags & KISS_FRAME) { | ||||
|         tnc_drop(tnc); | ||||
| 
 | ||||
|         errno = 0; | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return (ssize_t)w; | ||||
| 
 | ||||
| error_io: | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, | ||||
|                             const void *buf, | ||||
|                             size_t len, | ||||
|                             int port) { | ||||
|     return patty_kiss_frame_send(tnc->fd, buf, len, port); | ||||
| } | ||||
|  |  | |||
|  | @ -432,7 +432,7 @@ int patty_ax25_server_if_add(patty_ax25_server *server, | |||
|                              patty_ax25_if *iface) { | ||||
|     int fd; | ||||
| 
 | ||||
|     if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { | ||||
|     if ((fd = patty_ax25_if_fd(iface)) >= 0) { | ||||
|         fd_watch(server, fd); | ||||
|     } | ||||
| 
 | ||||
|  | @ -456,7 +456,7 @@ int patty_ax25_server_if_delete(patty_ax25_server *server, | |||
|         patty_ax25_if *iface = item->value; | ||||
| 
 | ||||
|         if (strncmp(iface->name, ifname, sizeof(iface->name)) == 0) { | ||||
|             if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { | ||||
|             if ((fd = patty_ax25_if_fd(iface)) >= 0) { | ||||
|                 fd_clear(server, fd); | ||||
|             } | ||||
| 
 | ||||
|  | @ -2006,7 +2006,7 @@ error_decode: | |||
| } | ||||
| 
 | ||||
| static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) { | ||||
|     int fd = patty_kiss_tnc_fd(iface->tnc); | ||||
|     int fd = patty_ax25_if_fd(iface); | ||||
| 
 | ||||
|     if (!FD_ISSET(fd, &server->fds_r)) { | ||||
|         goto done; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include <errno.h> | ||||
| 
 | ||||
| #include <patty/ax25.h> | ||||
| #include <patty/kiss/tnc.h> | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
|  | @ -621,15 +622,13 @@ error_invalid_type: | |||
| ssize_t patty_ax25_sock_recv(patty_ax25_sock *sock, | ||||
|                              void *buf, | ||||
|                              size_t len) { | ||||
|     int port; | ||||
| 
 | ||||
|     if (sock->type != PATTY_AX25_SOCK_RAW) { | ||||
|         errno = EINVAL; | ||||
| 
 | ||||
|         goto error_invalid_type; | ||||
|     } | ||||
| 
 | ||||
|     return patty_kiss_tnc_recv(sock->raw, buf, len, &port); | ||||
|     return patty_kiss_tnc_recv(sock->raw, buf, len); | ||||
| 
 | ||||
| error_invalid_type: | ||||
|     return -1; | ||||
|  |  | |||
							
								
								
									
										348
									
								
								src/tnc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/tnc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,348 @@ | |||
| #define _GNU_SOURCE | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <inttypes.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <termios.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <patty/kiss.h> | ||||
| #include <patty/kiss/tnc.h> | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| enum state_flags { | ||||
|     STATE_NONE    = 0, | ||||
|     STATE_FRAME   = 1 << 0, | ||||
|     STATE_COMMAND = 1 << 1, | ||||
|     STATE_ESCAPE  = 1 << 2 | ||||
| }; | ||||
| 
 | ||||
| enum tnc_opts { | ||||
|     TNC_NONE             = 0, | ||||
|     TNC_CLOSE_ON_DESTROY = 1 << 0 | ||||
| }; | ||||
| 
 | ||||
| struct _patty_kiss_tnc { | ||||
|     struct termios attrs, | ||||
|                    attrs_old; | ||||
| 
 | ||||
|     int fd, | ||||
|         opts; | ||||
| 
 | ||||
|     void *buf, | ||||
|          *frame; | ||||
| 
 | ||||
|     size_t bufsz, | ||||
|            offset, | ||||
|            dropped; | ||||
| 
 | ||||
|     ssize_t readlen; | ||||
| }; | ||||
| 
 | ||||
| patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { | ||||
|     patty_kiss_tnc *tnc; | ||||
| 
 | ||||
|     if ((tnc = malloc(sizeof(*tnc))) == NULL) { | ||||
|         goto error_malloc_tnc; | ||||
|     } | ||||
| 
 | ||||
|     if ((tnc->buf = malloc(PATTY_KISS_TNC_BUFSZ)) == NULL) { | ||||
|         goto error_malloc_buf; | ||||
|     } | ||||
| 
 | ||||
|     if (info->flags & PATTY_KISS_TNC_DEVICE) { | ||||
|         struct stat st; | ||||
| 
 | ||||
|         if (strcmp(info->device, "/dev/ptmx") == 0) { | ||||
|             int ptysub; | ||||
| 
 | ||||
|             if (openpty(&tnc->fd, &ptysub, NULL, NULL, NULL) < 0) { | ||||
|                 goto error_open; | ||||
|             } | ||||
|         } else if (stat(info->device, &st) < 0) { | ||||
|             goto error_stat; | ||||
|         } else if ((st.st_mode & S_IFMT) == S_IFSOCK) { | ||||
|             struct sockaddr_un addr; | ||||
| 
 | ||||
|             if (strlen(info->device) > sizeof(addr.sun_path)) { | ||||
|                 errno = EOVERFLOW; | ||||
| 
 | ||||
|                 goto error_overflow; | ||||
|             } | ||||
| 
 | ||||
|             if ((tnc->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
|                 goto error_socket; | ||||
|             } | ||||
| 
 | ||||
|             memset(&addr, '\0', sizeof(addr)); | ||||
|             addr.sun_family = AF_UNIX; | ||||
|             strncpy(addr.sun_path, info->device, sizeof(addr.sun_path)-1); | ||||
| 
 | ||||
|             if (connect(tnc->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||||
|                 goto error_connect; | ||||
|             } | ||||
|         } else { | ||||
|             if ((tnc->fd = open(info->device, O_RDWR | O_NOCTTY)) < 0) { | ||||
|                 goto error_open; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tnc->opts |= TNC_CLOSE_ON_DESTROY; | ||||
|     } else if (info->flags & PATTY_KISS_TNC_FD) { | ||||
|         tnc->fd = info->fd; | ||||
|     } else { | ||||
|         errno = EINVAL; | ||||
| 
 | ||||
|         goto error_no_fd; | ||||
|     } | ||||
| 
 | ||||
|     if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) { | ||||
|         if (tcgetattr(tnc->fd, &tnc->attrs) < 0) { | ||||
|             goto error_tcgetattr; | ||||
|         } | ||||
| 
 | ||||
|         memcpy(&tnc->attrs_old, &tnc->attrs, sizeof(tnc->attrs_old)); | ||||
| 
 | ||||
|         cfmakeraw(&tnc->attrs); | ||||
| 
 | ||||
|         if (info->flags & PATTY_KISS_TNC_BAUD) { | ||||
|             cfsetspeed(&tnc->attrs, info->baud); | ||||
|         } | ||||
| 
 | ||||
|         if (info->flags & PATTY_KISS_TNC_FLOW) { | ||||
|             switch (info->flow) { | ||||
|                 case PATTY_KISS_TNC_FLOW_NONE: | ||||
|                     break; | ||||
| 
 | ||||
|                 case PATTY_KISS_TNC_FLOW_CRTSCTS: | ||||
|                     tnc->attrs.c_cflag |= CRTSCTS; | ||||
| 
 | ||||
|                     break; | ||||
| 
 | ||||
|                 case PATTY_KISS_TNC_FLOW_XONXOFF: | ||||
|                     tnc->attrs.c_iflag |= IXON | IXOFF; | ||||
| 
 | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (tcflush(tnc->fd, TCIOFLUSH) < 0) { | ||||
|             goto error_tcflush; | ||||
|         } | ||||
| 
 | ||||
|         if (tcsetattr(tnc->fd, TCSANOW, &tnc->attrs) < 0) { | ||||
|             goto error_tcsetattr; | ||||
|         } | ||||
|     } else { | ||||
|         errno = 0; | ||||
|     } | ||||
| 
 | ||||
|     tnc->opts    =  TNC_NONE; | ||||
|     tnc->bufsz   =  PATTY_KISS_TNC_BUFSZ; | ||||
|     tnc->offset  =  0; | ||||
|     tnc->dropped =  0; | ||||
|     tnc->readlen = -1; | ||||
| 
 | ||||
|     return tnc; | ||||
| 
 | ||||
| error_tcflush: | ||||
| error_tcsetattr: | ||||
| error_tcgetattr: | ||||
| error_connect: | ||||
|     if (info->flags & PATTY_KISS_TNC_DEVICE) { | ||||
|         (void)close(tnc->fd); | ||||
|     } | ||||
| 
 | ||||
| error_open: | ||||
| error_no_fd: | ||||
| error_socket: | ||||
| error_overflow: | ||||
| error_stat: | ||||
|     free(tnc->buf); | ||||
| 
 | ||||
| error_malloc_buf: | ||||
|     free(tnc); | ||||
| 
 | ||||
| error_malloc_tnc: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc) { | ||||
|     if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) { | ||||
|         (void)tcsetattr(tnc->fd, TCSANOW, &tnc->attrs_old); | ||||
|     } | ||||
| 
 | ||||
|     if (tnc->opts & TNC_CLOSE_ON_DESTROY) { | ||||
|         (void)close(tnc->fd); | ||||
|     } | ||||
| 
 | ||||
|     free(tnc->buf); | ||||
|     free(tnc); | ||||
| } | ||||
| 
 | ||||
| int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) { | ||||
|     return tnc->fd; | ||||
| } | ||||
| 
 | ||||
| static void tnc_drop(patty_kiss_tnc *tnc) { | ||||
|     tnc->offset  =  0; | ||||
|     tnc->readlen = -1; | ||||
|     tnc->dropped++; | ||||
| } | ||||
| 
 | ||||
| size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) { | ||||
|     return tnc->dropped; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc) { | ||||
|     if (tnc->readlen < 0) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (tnc->offset == 0) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return tnc->readlen - tnc->offset; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, | ||||
|                             void *buf, | ||||
|                             size_t len) { | ||||
|     size_t r = 0, /* Number of bytes read */ | ||||
|            w = 0; /* Number of bytes written to buf */ | ||||
| 
 | ||||
|     int flags = STATE_NONE; | ||||
| 
 | ||||
|     if (tnc->offset == tnc->readlen) { | ||||
|         errno = 0; | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     while (1) { | ||||
|         uint8_t c; | ||||
| 
 | ||||
|         r++; | ||||
| 
 | ||||
|         if (w == len) { | ||||
|             tnc_drop(tnc); | ||||
| 
 | ||||
|             flags &= ~STATE_FRAME; | ||||
|                 w  = 0; | ||||
|         } | ||||
| 
 | ||||
|         if (tnc->offset == 0) { | ||||
|             if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) { | ||||
|                 goto error_io; | ||||
|             } else if (tnc->readlen == 0) { | ||||
|                 goto done; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         c = ((uint8_t *)tnc->buf)[tnc->offset++]; | ||||
| 
 | ||||
|         if (tnc->offset == tnc->readlen) { | ||||
|             tnc->offset = 0; | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & STATE_FRAME)) { | ||||
|             if (c == PATTY_KISS_FEND) { | ||||
|                 flags = STATE_FRAME; | ||||
| 
 | ||||
|                 continue; | ||||
|             } else { | ||||
|                 errno = EIO; | ||||
| 
 | ||||
|                 goto error_io; | ||||
|             } | ||||
|         } else { | ||||
|             if (c == PATTY_KISS_FEND) { | ||||
|                 flags = STATE_NONE; | ||||
| 
 | ||||
|                 if (w > 0) { | ||||
|                     goto done; | ||||
|                 } | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & STATE_COMMAND)) { | ||||
|             if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { | ||||
|                 errno = EIO; | ||||
| 
 | ||||
|                 goto error_io; | ||||
|             } | ||||
| 
 | ||||
|             flags |= STATE_COMMAND; | ||||
| 
 | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (!(flags & STATE_ESCAPE)) { | ||||
|             if (c == PATTY_KISS_FESC) { | ||||
|                 flags |= STATE_ESCAPE; | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
|         } else { | ||||
|             switch (c) { | ||||
|                 case PATTY_KISS_TFEND: | ||||
|                     ((uint8_t *)buf)[w++] = PATTY_KISS_FEND; | ||||
|                     flags &= ~STATE_ESCAPE; | ||||
|                     continue; | ||||
| 
 | ||||
|                 case PATTY_KISS_TFESC: | ||||
|                     ((uint8_t *)buf)[w++] = PATTY_KISS_FESC; | ||||
|                     flags &= ~STATE_ESCAPE; | ||||
|                     continue; | ||||
| 
 | ||||
|                 default: | ||||
|                     errno = EIO; | ||||
| 
 | ||||
|                     goto error_io; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ((uint8_t *)buf)[w++] = c; | ||||
|     } | ||||
| 
 | ||||
| done: | ||||
|     if (flags & STATE_FRAME) { | ||||
|         tnc_drop(tnc); | ||||
| 
 | ||||
|         errno = 0; | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return (ssize_t)w; | ||||
| 
 | ||||
| error_io: | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, | ||||
|                             const void *buf, | ||||
|                             size_t len) { | ||||
|     return patty_kiss_frame_send(tnc->fd, buf, len, PATTY_KISS_TNC_PORT); | ||||
| } | ||||
| 
 | ||||
| patty_ax25_if_driver *patty_kiss_tnc_driver() { | ||||
|     static patty_ax25_if_driver driver = { | ||||
|         .destroy = (patty_ax25_if_driver_destroy *)patty_kiss_tnc_destroy, | ||||
|         .fd      = (patty_ax25_if_driver_fd *)patty_kiss_tnc_fd, | ||||
|         .pending = (patty_ax25_if_driver_pending *)patty_kiss_tnc_pending, | ||||
|         .recv    = (patty_ax25_if_driver_recv *)patty_kiss_tnc_recv, | ||||
|         .send    = (patty_ax25_if_driver_send *)patty_kiss_tnc_send | ||||
|     }; | ||||
| 
 | ||||
|     return &driver; | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue