summaryrefslogtreecommitdiff
path: root/lib/pcap-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pcap-file.c')
-rw-r--r--lib/pcap-file.c102
1 files changed, 71 insertions, 31 deletions
diff --git a/lib/pcap-file.c b/lib/pcap-file.c
index ea5cfa3b2..81a094c2a 100644
--- a/lib/pcap-file.c
+++ b/lib/pcap-file.c
@@ -34,6 +34,16 @@
VLOG_DEFINE_THIS_MODULE(pcap);
+enum ts_resolution {
+ PCAP_USEC,
+ PCAP_NSEC,
+};
+
+struct pcap_file {
+ FILE *file;
+ enum ts_resolution resolution;
+};
+
struct pcap_hdr {
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
@@ -47,25 +57,27 @@ BUILD_ASSERT_DECL(sizeof(struct pcap_hdr) == 24);
struct pcaprec_hdr {
uint32_t ts_sec; /* timestamp seconds */
- uint32_t ts_usec; /* timestamp microseconds */
+ uint32_t ts_subsec; /* timestamp subseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
};
BUILD_ASSERT_DECL(sizeof(struct pcaprec_hdr) == 16);
-FILE *
+struct pcap_file *
ovs_pcap_open(const char *file_name, const char *mode)
{
struct stat s;
- FILE *file;
+ struct pcap_file *p_file;
int error;
ovs_assert(!strcmp(mode, "rb") ||
!strcmp(mode, "wb") ||
!strcmp(mode, "ab"));
- file = fopen(file_name, mode);
- if (file == NULL) {
+ p_file = xmalloc(sizeof *p_file);
+ p_file->file = fopen(file_name, mode);
+ p_file->resolution = PCAP_USEC;
+ if (p_file->file == NULL) {
VLOG_WARN("%s: failed to open pcap file for %s (%s)", file_name,
(mode[0] == 'r' ? "reading"
: mode[0] == 'w' ? "writing"
@@ -76,49 +88,64 @@ ovs_pcap_open(const char *file_name, const char *mode)
switch (mode[0]) {
case 'r':
- error = ovs_pcap_read_header(file);
+ error = ovs_pcap_read_header(p_file);
if (error) {
errno = error;
- fclose(file);
+ ovs_pcap_close(p_file);
return NULL;
}
break;
case 'w':
- ovs_pcap_write_header(file);
+ ovs_pcap_write_header(p_file);
break;
case 'a':
- if (!fstat(fileno(file), &s) && !s.st_size) {
- ovs_pcap_write_header(file);
+ if (!fstat(fileno(p_file->file), &s) && !s.st_size) {
+ ovs_pcap_write_header(p_file);
}
break;
default:
OVS_NOT_REACHED();
}
- return file;
+
+ return p_file;
+}
+
+struct pcap_file *
+ovs_pcap_stdout(void)
+{
+ struct pcap_file *p_file = xmalloc(sizeof *p_file);
+ p_file->file = stdout;
+ return p_file;
}
int
-ovs_pcap_read_header(FILE *file)
+ovs_pcap_read_header(struct pcap_file *p_file)
{
struct pcap_hdr ph;
- if (fread(&ph, sizeof ph, 1, file) != 1) {
- int error = ferror(file) ? errno : EOF;
+ if (fread(&ph, sizeof ph, 1, p_file->file) != 1) {
+ int error = ferror(p_file->file) ? errno : EOF;
VLOG_WARN("failed to read pcap header: %s", ovs_retval_to_string(error));
return error;
}
- if (ph.magic_number != 0xa1b2c3d4 && ph.magic_number != 0xd4c3b2a1) {
+ if (ph.magic_number == 0xa1b2c3d4 || ph.magic_number == 0xd4c3b2a1) {
+ p_file->resolution = PCAP_USEC;
+ } else if (ph.magic_number == 0xa1b23c4d ||
+ ph.magic_number == 0x4d3cb2a1) {
+ p_file->resolution = PCAP_NSEC;
+ } else {
VLOG_WARN("bad magic 0x%08"PRIx32" reading pcap file "
- "(expected 0xa1b2c3d4 or 0xd4c3b2a1)", ph.magic_number);
+ "(expected 0xa1b2c3d4, 0xa1b23c4d, 0xd4c3b2a1, "
+ "or 0x4d3cb2a1)", ph.magic_number);
return EPROTO;
}
return 0;
}
void
-ovs_pcap_write_header(FILE *file)
+ovs_pcap_write_header(struct pcap_file *p_file)
{
/* The pcap reader is responsible for figuring out endianness based on the
* magic number, so the lack of htonX calls here is intentional. */
@@ -130,12 +157,13 @@ ovs_pcap_write_header(FILE *file)
ph.sigfigs = 0;
ph.snaplen = 1518;
ph.network = 1; /* Ethernet */
- ignore(fwrite(&ph, sizeof ph, 1, file));
- fflush(file);
+ ignore(fwrite(&ph, sizeof ph, 1, p_file->file));
+ fflush(p_file->file);
}
int
-ovs_pcap_read(FILE *file, struct dp_packet **bufp, long long int *when)
+ovs_pcap_read(struct pcap_file *p_file, struct dp_packet **bufp,
+ long long int *when)
{
struct pcaprec_hdr prh;
struct dp_packet *buf;
@@ -146,8 +174,8 @@ ovs_pcap_read(FILE *file, struct dp_packet **bufp, long long int *when)
*bufp = NULL;
/* Read header. */
- if (fread(&prh, sizeof prh, 1, file) != 1) {
- if (ferror(file)) {
+ if (fread(&prh, sizeof prh, 1, p_file->file) != 1) {
+ if (ferror(p_file->file)) {
int error = errno;
VLOG_WARN("failed to read pcap record header: %s",
ovs_retval_to_string(error));
@@ -173,15 +201,18 @@ ovs_pcap_read(FILE *file, struct dp_packet **bufp, long long int *when)
/* Calculate time. */
if (when) {
uint32_t ts_sec = swap ? uint32_byteswap(prh.ts_sec) : prh.ts_sec;
- uint32_t ts_usec = swap ? uint32_byteswap(prh.ts_usec) : prh.ts_usec;
- *when = ts_sec * 1000LL + ts_usec / 1000;
+ uint32_t ts_subsec = swap ? uint32_byteswap(prh.ts_subsec)
+ : prh.ts_subsec;
+ ts_subsec = p_file->resolution == PCAP_USEC ? ts_subsec / 1000
+ : ts_subsec / 1000000;
+ *when = ts_sec * 1000LL + ts_subsec;
}
/* Read packet. Packet type is Ethernet */
buf = dp_packet_new(len);
data = dp_packet_put_uninit(buf, len);
- if (fread(data, len, 1, file) != 1) {
- int error = ferror(file) ? errno : EOF;
+ if (fread(data, len, 1, p_file->file) != 1) {
+ int error = ferror(p_file->file) ? errno : EOF;
VLOG_WARN("failed to read pcap packet: %s",
ovs_retval_to_string(error));
dp_packet_delete(buf);
@@ -192,7 +223,7 @@ ovs_pcap_read(FILE *file, struct dp_packet **bufp, long long int *when)
}
void
-ovs_pcap_write(FILE *file, struct dp_packet *buf)
+ovs_pcap_write(struct pcap_file *p_file, struct dp_packet *buf)
{
struct pcaprec_hdr prh;
struct timeval tv;
@@ -201,12 +232,21 @@ ovs_pcap_write(FILE *file, struct dp_packet *buf)
xgettimeofday(&tv);
prh.ts_sec = tv.tv_sec;
- prh.ts_usec = tv.tv_usec;
+ prh.ts_subsec = tv.tv_usec;
prh.incl_len = dp_packet_size(buf);
prh.orig_len = dp_packet_size(buf);
- ignore(fwrite(&prh, sizeof prh, 1, file));
- ignore(fwrite(dp_packet_data(buf), dp_packet_size(buf), 1, file));
- fflush(file);
+ ignore(fwrite(&prh, sizeof prh, 1, p_file->file));
+ ignore(fwrite(dp_packet_data(buf), dp_packet_size(buf), 1, p_file->file));
+ fflush(p_file->file);
+}
+
+void
+ovs_pcap_close(struct pcap_file *p_file)
+{
+ if (p_file->file != stdout) {
+ fclose(p_file->file);
+ }
+ free(p_file);
}
struct tcp_key {