int check_tun(const struct arguments *args, const struct epoll_event *ev, const int epoll_fd, int sessions, int maxsessions) { // Check tun error if (ev->events & EPOLLERR) { log_android(ANDROID_LOG_ERROR, "tun %d exception", args->tun); if (fcntl(args->tun, F_GETFL) < 0) { log_android(ANDROID_LOG_ERROR, "fcntl tun %d F_GETFL error %d: %s", args->tun, errno, strerror(errno)); report_exit(args, "fcntl tun %d F_GETFL error %d: %s", args->tun, errno, strerror(errno)); } else report_exit(args, "tun %d exception", args->tun); return -1; } // Check tun read if (ev->events & EPOLLIN) { uint8_t *buffer = malloc(get_mtu()); ssize_t length = read(args->tun, buffer, get_mtu()); if (length < 0) { free(buffer); log_android(ANDROID_LOG_ERROR, "tun %d read error %d: %s", args->tun, errno, strerror(errno)); if (errno == EINTR || errno == EAGAIN) // Retry later return 0; else { report_exit(args, "tun %d read error %d: %s", args->tun, errno, strerror(errno)); return -1; } } else if (length > 0) { // Write pcap record if (pcap_file != NULL) write_pcap_rec(buffer, (size_t) length); if (length > max_tun_msg) { max_tun_msg = length; log_android(ANDROID_LOG_WARN, "Maximum tun msg length %d", max_tun_msg); } // Handle IP from tun handle_ip(args, buffer, (size_t) length, epoll_fd, sessions, maxsessions); free(buffer); } else { // tun eof free(buffer); log_android(ANDROID_LOG_ERROR, "tun %d empty read", args->tun); report_exit(args, "tun %d empty read", args->tun); return -1; } } return 0; }
static void write_pcap_hdr(FILE *file) { struct pcap_file_header hdr = { .magic = PCAP_FILE_MAGIC, .version_major = 2, .version_minor = 4, .thiszone = 0, .sigfigs = 0, .snaplen = MAX_PSDU, .linktype = DLT_IEEE802_15_4 }; if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) { perror("fwrite"); exit(1); } } static void write_pcap_rec(FILE *file, const struct timeval *tv, const void *buf, int n) { struct pcap_pkthdr hdr = { .ts_sec = tv->tv_sec, .ts_usec = tv->tv_usec, .caplen = n, .len = n }; if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) { perror("fwrite"); exit(1); } if (fwrite(buf, n, 1, file) != 1) { perror("fwrite"); exit(1); } } static void receive_pcap(struct atrf_dsc *dsc, const char *name) { FILE *file; uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */ struct timeval now; int n; int count = 0; file = fopen(name, "w"); if (!file) { perror(name); exit(1); } write_pcap_hdr(file); while (run) { wait_for_interrupt(dsc, IRQ_TRX_END, quick ? 0xff : IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, quick ? -1 : 0); if (!run) break; gettimeofday(&now, NULL); n = atrf_buf_read(dsc, buf, sizeof(buf)); if (n < 0) exit(1); if (n < 2) { fprintf(stderr, "%d bytes received\n", n); continue; } write_pcap_rec(file, &now, buf, n-1); if (!quick) (void) write(2, ".", 1); count++; } if (fclose(file) == EOF) { perror(name); exit(1); } fprintf(stderr, "%sreceived %d message%s\n", count ? "\n" : "", count, count == 1 ? "" : "s"); } static void receive(struct atrf_dsc *dsc, const char *name, int hex) { atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON); /* * 180 us, according to AVR2001 section 4.2. We time out after * nominally 200 us. */ wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1); if (name) receive_pcap(dsc, name); else receive_message(dsc, hex); }