diff --git a/examples/Makefile b/examples/Makefile index a26d5c0..6894689 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -7,7 +7,7 @@ INCLUDE_PATH = ../include CFLAGS += -I$(INCLUDE_PATH) LDFLAGS = -L../src -lhexagram -EXAMPLES = pcapread +EXAMPLES = convert pcapread RM = /bin/rm diff --git a/examples/convert.c b/examples/convert.c new file mode 100644 index 0000000..f4e9797 --- /dev/null +++ b/examples/convert.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; + uint8_t body[65535]; + + 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; + } + + /* + * Read the packet body into our scratchpad. + */ + if ((readlen = read(stream->fd, &body, header.caplen)) < 0) { + stream->error = HEXAGRAM_PCAPNG_ERROR_IO; + + goto error_io; + } else { + remaining -= readlen; + total += readlen; + } + + usec = (uint64_t)header.timestamp[0] << 32 + | (uint64_t)header.timestamp[1]; + + timestamp.tv_sec = usec / 1000000; + timestamp.tv_usec = usec % 1000000; + + ((struct can_frame *)body)->can_id = be32toh(((struct can_frame *)body)->can_id); + + if (hexagram_capture_write(capture, (struct can_frame *)body, ×tamp) < 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; + } + + fprintf(stderr, "Read block type %08"PRIx32" len %zu\n", + type, len); + + if (lseek(stream->fd, len, SEEK_CUR) < 0) { + stream->error = HEXAGRAM_PCAPNG_ERROR_IO; + + goto error_io; + } + + return len; + +error_io: + return -1; +} + +int main(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; +} diff --git a/include/hexagram/can.h b/include/hexagram/can.h deleted file mode 100644 index 6418761..0000000 --- a/include/hexagram/can.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _HEXAGRAM_CAN_H -#define _HEXAGRAM_CAN_H - -#include -#include -#include - -#define HEXAGRAM_CAN_DUMP_MAGIC "CAAN" -#define HEXAGRAM_CAN_DUMP_ENDIAN 0x0a0b0c0d -#define HEXAGRAM_CAN_DUMP_ENDIAN_SWAPPED 0x0d0c0b0a - -#define HEXAGRAM_CAN_DUMP_TYPE_UNKNOWN 0 -#define HEXAGRAM_CAN_DUMP_TYPE_SOCKETCAN 29 - -#define HEXAGRAM_CAN_DUMP_TSRESOL_USEC 6 - -typedef struct _hexagram_can_dump { - char magic[4]; - uint32_t endian; - uint8_t type, - tsresol; - char iface[38]; -} hexagram_can_dump; - -typedef struct _hexagram_can_frame { - uint32_t timestamp_hi, - timestamp_lo; - struct can_frame frame; -} hexagram_can_frame; - -typedef struct _hexagram_can_stream hexagram_can_stream; - -hexagram_can_stream *hexagram_can_stream_open_fd(int fd); - -hexagram_can_stream *hexagram_can_stream_create_file(const char *file, - const char *iface); - -void hexagram_can_stream_destroy(hexagram_can_stream *stream); - -int hexagram_can_stream_read(hexagram_can_stream *stream, - uint32_t *timestamp_hi, - uint32_t *timestamp_lo, - struct can_frame *frame); - -int hexagram_can_stream_write(hexagram_can_stream *stream, - struct can_frame *frame); - -#endif /* _HEXAGRAM_CAN_H */ diff --git a/include/hexagram/capture.h b/include/hexagram/capture.h new file mode 100644 index 0000000..2c4da35 --- /dev/null +++ b/include/hexagram/capture.h @@ -0,0 +1,41 @@ +#ifndef _HEXAGRAM_CAPTURE_H +#define _HEXAGRAM_CAPTURE_H + +#include +#include +#include +#include + +#define HEXAGRAM_CAPTURE_MAGIC "HCAN" +#define HEXAGRAM_CAPTURE_ENDIAN 0x0a0b0c0d +#define HEXAGRAM_CAPTURE_ENDIAN_SWAPPED 0x0d0c0b0a + +typedef struct _hexagram_capture hexagram_capture; + +typedef struct _hexagram_capture_header { + char magic[4]; + uint32_t endian; +} hexagram_capture_header; + +typedef struct _hexagram_capture_frame { + uint32_t timestamp_hi, + timestamp_lo; + struct can_frame frame; +} hexagram_capture_frame; + +hexagram_capture *hexagram_capture_open_fd(int fd, int flags); + +hexagram_capture *hexagram_capture_open_file(const char *file, int flags); + +void hexagram_capture_destroy(hexagram_capture *capture); + +int hexagram_capture_read(hexagram_capture *capture, + uint32_t *timestamp_hi, + uint32_t *timestamp_lo, + struct can_frame *frame); + +int hexagram_capture_write(hexagram_capture *capture, + struct can_frame *frame, + struct timeval *timestamp); + +#endif /* _HEXAGRAM_CAPTURE_H */ diff --git a/src/Makefile b/src/Makefile index 0cff3b6..36a89db 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,10 +7,10 @@ CC = $(CROSS)cc CFLAGS += -fPIC -I$(INCLUDE_PATH) LDFLAGS = -HEADERS = can.h pcapng.h +HEADERS = capture.h pcapng.h HEADERS_LOCAL = util.h -OBJS = can.o pcapng.o +OBJS = capture.o pcapng.o VERSION_MAJOR = 0 VERSION_MINOR = 0.1 diff --git a/src/can.c b/src/can.c deleted file mode 100644 index 24d234f..0000000 --- a/src/can.c +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -struct _hexagram_can_stream { - int fd; - uint32_t endian; - uint8_t tsresol; -}; - -hexagram_can_stream *hexagram_can_stream_open_fd(int fd) { - hexagram_can_stream *stream; - hexagram_can_dump dump; - ssize_t readlen; - - if ((stream = malloc(sizeof(*stream))) == NULL) { - goto error_malloc; - } - - if ((readlen = read(fd, &dump, sizeof(dump))) < 0) { - goto error_read; - } - - if (memcmp(dump.magic, HEXAGRAM_CAN_DUMP_MAGIC, sizeof(dump.magic)) != 0) { - goto error_invalid_format; - } - - switch (dump.endian) { - case HEXAGRAM_CAN_DUMP_ENDIAN: - case HEXAGRAM_CAN_DUMP_ENDIAN_SWAPPED: - break; - - default: - goto error_invalid_format; - } - - if (dump.type != HEXAGRAM_CAN_DUMP_TYPE_SOCKETCAN) { - goto error_invalid_format; - } - - stream->fd = fd; - stream->endian = dump.endian; - stream->tsresol = dump.tsresol; - - return stream; - -error_invalid_format: -error_read: - free(stream); - -error_malloc: - return NULL; -} - -hexagram_can_stream *hexagram_can_stream_create_file(const char *file, - const char *iface) { - int fd; - hexagram_can_dump header; - - if ((fd = open(file, O_CREAT | O_WRONLY)) < 0) { - goto error_open; - } - - memcpy(header.magic, HEXAGRAM_CAN_DUMP_MAGIC, strlen(HEXAGRAM_CAN_DUMP_MAGIC)); - - header.endian = HEXAGRAM_CAN_DUMP_ENDIAN; - header.type = PF_CAN; - header.tsresol = HEXAGRAM_CAN_DUMP_TSRESOL_USEC; - - strncpy(header.iface, iface, sizeof(header.iface)); - - if (write(fd, &header, sizeof(header)) < 0) { - goto error_write; - } - - return hexagram_can_stream_open_fd(fd); - -error_write: - close(fd); - -error_open: - return NULL; -} - -void hexagram_can_stream_destroy(hexagram_can_stream *stream) { - memset(stream, '\0', sizeof(*stream)); - - free(stream); -} - -int hexagram_can_stream_read(hexagram_can_stream *stream, - uint32_t *timestamp_hi, - uint32_t *timestamp_lo, - struct can_frame *frame) { - ssize_t len; - hexagram_can_frame data; - - if ((len = read(stream->fd, &data, sizeof(data))) < 0) { - goto error_io; - } else if (len < sizeof(data)) { - goto error_io; - } - - *timestamp_hi = data.timestamp_hi; - *timestamp_lo = data.timestamp_lo; - - memcpy(frame, &data.frame, sizeof(data.frame)); - - return 0; - -error_io: - return -1; -} - -int hexagram_can_stream_write(hexagram_can_stream *stream, - struct can_frame *frame) { - hexagram_can_frame data; - struct timeval now; - - if (gettimeofday(&now, NULL) < 0) { - goto error_gettimeofday; - } - - data.timestamp_hi = now.tv_usec & 0xffffffff00000000 >> 32; - data.timestamp_lo = now.tv_usec & 0x00000000ffffffff; - - memcpy(&data.frame, frame, sizeof(data.frame)); - - return write(stream->fd, &data, sizeof(data)); - -error_gettimeofday: - return -1; -} diff --git a/src/capture.c b/src/capture.c new file mode 100644 index 0000000..ccb3433 --- /dev/null +++ b/src/capture.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include + +#include + +struct _hexagram_capture { + int fd; + uint32_t endian; +}; + +hexagram_capture *hexagram_capture_open_fd(int fd, int flags) { + hexagram_capture *capture; + hexagram_capture_header header; + + if ((capture = malloc(sizeof(*capture))) == NULL) { + goto error_malloc; + } + + if (flags & O_WRONLY && !(flags & O_APPEND)) { + memcpy(header.magic, HEXAGRAM_CAPTURE_MAGIC, strlen(HEXAGRAM_CAPTURE_MAGIC)); + + header.endian = HEXAGRAM_CAPTURE_ENDIAN; + + if (write(fd, &header, sizeof(header)) < 0) { + goto error_io; + } + } else if (flags & O_RDONLY) { + ssize_t readlen; + + if ((readlen = read(fd, &header, sizeof(header))) < 0) { + goto error_io; + } + + if (memcmp(header.magic, HEXAGRAM_CAPTURE_MAGIC, sizeof(header.magic)) != 0) { + goto error_invalid_format; + } + + switch (header.endian) { + case HEXAGRAM_CAPTURE_ENDIAN: + case HEXAGRAM_CAPTURE_ENDIAN_SWAPPED: + break; + + default: + goto error_invalid_format; + } + } + + capture->fd = fd; + capture->endian = header.endian; + + return capture; + +error_invalid_format: +error_io: + free(capture); + +error_malloc: + return NULL; +} + +hexagram_capture *hexagram_capture_open_file(const char *file, int flags) { + int fd = (flags & O_CREAT)? + open(file, flags, 0644): + open(file, flags); + + if (fd < 0) { + return NULL; + } + + return hexagram_capture_open_fd(fd, flags); +} + +void hexagram_capture_destroy(hexagram_capture *capture) { + memset(capture, '\0', sizeof(*capture)); + + free(capture); +} + +int hexagram_capture_read(hexagram_capture *capture, + uint32_t *timestamp_hi, + uint32_t *timestamp_lo, + struct can_frame *frame) { + ssize_t len; + hexagram_capture_frame data; + + if ((len = read(capture->fd, &data, sizeof(data))) < 0) { + goto error_io; + } else if (len < sizeof(data)) { + goto error_io; + } + + *timestamp_hi = data.timestamp_hi; + *timestamp_lo = data.timestamp_lo; + + memcpy(frame, &data.frame, sizeof(data.frame)); + + return 0; + +error_io: + return -1; +} + +int hexagram_capture_write(hexagram_capture *capture, + struct can_frame *frame, + struct timeval *timestamp) { + hexagram_capture_frame data; + + if (timestamp == NULL) { + struct timeval now; + + if (gettimeofday(&now, NULL) < 0) { + goto error_gettimeofday; + } + + data.timestamp_hi = now.tv_usec & 0xffffffff00000000 >> 32; + data.timestamp_lo = now.tv_usec & 0x00000000ffffffff; + } else { + data.timestamp_hi = timestamp->tv_usec & 0xffffffff00000000 >> 32; + data.timestamp_lo = timestamp->tv_usec & 0x00000000ffffffff; + } + + memcpy(&data.frame, frame, sizeof(data.frame)); + + return write(capture->fd, &data, sizeof(data)); + +error_gettimeofday: + return -1; +} diff --git a/src/pcapng.c b/src/pcapng.c index 0e24acf..8f83b88 100644 --- a/src/pcapng.c +++ b/src/pcapng.c @@ -16,6 +16,10 @@ ssize_t hexagram_pcapng_read_options(hexagram_pcapng_stream *stream, hexagram_pcapng_option option; ssize_t total = 0; + if (handler == NULL) { + goto error_no_handler; + } + while (total < len) { ssize_t readlen; @@ -53,6 +57,7 @@ ssize_t hexagram_pcapng_read_options(hexagram_pcapng_stream *stream, return total; error_io: +error_no_handler: return -1; } @@ -86,6 +91,10 @@ ssize_t hexagram_pcapng_stream_read(hexagram_pcapng_stream *stream, hexagram_pcapng_block_footer footer; ssize_t total = 0; + if (handler == NULL) { + goto error_no_handler; + } + while (1) { size_t expected; ssize_t readlen; @@ -137,5 +146,6 @@ done: return total; error_io: +error_no_handler: return -1; }