256 lines
6 KiB
C
256 lines
6 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <inttypes.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <endian.h>
|
|
|
|
#include <hexagram/capture.h>
|
|
#include <hexagram/pcapng.h>
|
|
|
|
char *hexagram_arglist_convert(void) {
|
|
return "[infile.pcapng] [outfile.can]";
|
|
}
|
|
|
|
static ssize_t handle_option(hexagram_pcapng_stream *stream,
|
|
uint32_t type,
|
|
uint16_t code,
|
|
uint16_t len,
|
|
void *data) {
|
|
if (lseek(stream->fd, (size_t)len, SEEK_CUR) < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_OK;
|
|
|
|
return (size_t)len;
|
|
|
|
error_io:
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t handle_block_if(hexagram_pcapng_stream *stream,
|
|
uint32_t type,
|
|
size_t len,
|
|
void *data) {
|
|
hexagram_pcapng_if iface;
|
|
|
|
ssize_t readlen,
|
|
total = 0;
|
|
|
|
size_t remaining = len;
|
|
|
|
/*
|
|
* Read the interface block header.
|
|
*/
|
|
if ((readlen = read(stream->fd, &iface, sizeof(iface))) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
} else {
|
|
remaining -= readlen;
|
|
total += readlen;
|
|
}
|
|
|
|
if ((readlen = hexagram_pcapng_read_options(stream, handle_option, type, remaining, data)) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
} else {
|
|
total += readlen;
|
|
}
|
|
|
|
return total;
|
|
|
|
error_io:
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t handle_block_packet(hexagram_pcapng_stream *stream,
|
|
uint32_t type,
|
|
size_t len,
|
|
hexagram_capture *capture) {
|
|
hexagram_pcapng_packet header;
|
|
struct can_frame frame;
|
|
|
|
ssize_t readlen,
|
|
total = 0;
|
|
|
|
size_t remaining = len;
|
|
|
|
struct timeval timestamp;
|
|
uint64_t usec;
|
|
|
|
/*
|
|
* Read the packet block header so that we may determine the size of the
|
|
* payload to continue to read.
|
|
*/
|
|
if ((readlen = read(stream->fd, &header, sizeof(header))) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
} else {
|
|
remaining -= readlen;
|
|
total += readlen;
|
|
}
|
|
|
|
if (header.caplen > sizeof(frame)) {
|
|
if (lseek(stream->fd, header.caplen, SEEK_CUR) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
}
|
|
|
|
readlen = header.caplen;
|
|
} else if ((readlen = read(stream->fd, &frame, header.caplen)) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
}
|
|
|
|
remaining -= readlen;
|
|
total += readlen;
|
|
|
|
if (header.caplen <= sizeof(frame)) {
|
|
usec = ((uint64_t)header.timestamp[0] << 32)
|
|
| (uint64_t)header.timestamp[1];
|
|
|
|
timestamp.tv_sec = usec / 1000000;
|
|
timestamp.tv_usec = usec % 1000000;
|
|
|
|
frame.can_id = be32toh(frame.can_id);
|
|
|
|
if (hexagram_capture_write(capture, ×tamp, &frame) < 0) {
|
|
goto error_io;
|
|
}
|
|
}
|
|
|
|
if (header.caplen % sizeof(uint32_t)) {
|
|
size_t padding = sizeof(uint32_t) - (header.caplen % sizeof(uint32_t));
|
|
|
|
if (lseek(stream->fd, padding, SEEK_CUR) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
} else {
|
|
remaining -= padding;
|
|
total += padding;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The remaining data here should be pcapng option values, and since we do
|
|
* not presently require them, we can safely seek past them.
|
|
*/
|
|
if (lseek(stream->fd, remaining, SEEK_CUR) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
} else {
|
|
total += remaining;
|
|
}
|
|
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_OK;
|
|
|
|
return total;
|
|
|
|
error_io:
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t handle_block(hexagram_pcapng_stream *stream,
|
|
uint32_t type,
|
|
size_t len,
|
|
void *data) {
|
|
switch (type) {
|
|
case HEXAGRAM_PCAPNG_BLOCK_IF:
|
|
return handle_block_if(stream, type, len, data);
|
|
|
|
case HEXAGRAM_PCAPNG_BLOCK_PACKET:
|
|
return handle_block_packet(stream, type, len, (hexagram_capture *)data);
|
|
|
|
default: break;
|
|
}
|
|
|
|
if (lseek(stream->fd, len, SEEK_CUR) < 0) {
|
|
stream->error = HEXAGRAM_PCAPNG_ERROR_IO;
|
|
|
|
goto error_io;
|
|
}
|
|
|
|
return len;
|
|
|
|
error_io:
|
|
return -1;
|
|
}
|
|
|
|
int hexagram_main_convert(int argc, char **argv) {
|
|
int fd;
|
|
|
|
hexagram_pcapng_stream *stream;
|
|
hexagram_capture *capture;
|
|
|
|
fd = (argc < 2)?
|
|
fileno(stdin):
|
|
open(argv[1], O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
perror("open()");
|
|
|
|
goto error_open_pcapng;
|
|
}
|
|
|
|
if (argc > 2) {
|
|
if ((capture = hexagram_capture_open_file(argv[2], O_CREAT | O_WRONLY)) == NULL) {
|
|
perror("hexagram_capture_open_file()");
|
|
|
|
goto error_capture_open;
|
|
}
|
|
} else {
|
|
if ((capture = hexagram_capture_open_fd(fileno(stdout), O_WRONLY)) == NULL) {
|
|
perror("hexagram_capture_open_fd()");
|
|
|
|
goto error_capture_open;
|
|
}
|
|
}
|
|
|
|
if ((stream = hexagram_pcapng_stream_open_fd(fd)) < 0) {
|
|
perror("hexagram_pcapng_stream_open_fd()");
|
|
|
|
goto error_pcapng_stream_open_fd;
|
|
}
|
|
|
|
if (hexagram_pcapng_stream_read(stream, handle_block, capture) < 0) {
|
|
perror("hexagram_pcapng_stream_read()");
|
|
|
|
goto error_pcapng_stream_read;
|
|
}
|
|
|
|
hexagram_pcapng_stream_destroy(stream);
|
|
|
|
hexagram_capture_destroy(capture);
|
|
|
|
if (argc == 2) {
|
|
close(fd);
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_pcapng_stream_read:
|
|
error_pcapng_stream_open_fd:
|
|
hexagram_pcapng_stream_destroy(stream);
|
|
|
|
error_capture_open:
|
|
if (argc == 3 || argc == 2) {
|
|
close(fd);
|
|
}
|
|
|
|
error_open_pcapng:
|
|
return 1;
|
|
}
|