~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/pcap-file.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2009, 2010, 2012 Nicira, Inc.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at:
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include <config.h>
 
18
#include "pcap-file.h"
 
19
#include <errno.h>
 
20
#include <inttypes.h>
 
21
#include <string.h>
 
22
#include "compiler.h"
 
23
#include "ofpbuf.h"
 
24
#include "vlog.h"
 
25
 
 
26
VLOG_DEFINE_THIS_MODULE(pcap);
 
27
 
 
28
struct pcap_hdr {
 
29
    uint32_t magic_number;   /* magic number */
 
30
    uint16_t version_major;  /* major version number */
 
31
    uint16_t version_minor;  /* minor version number */
 
32
    int32_t thiszone;        /* GMT to local correction */
 
33
    uint32_t sigfigs;        /* accuracy of timestamps */
 
34
    uint32_t snaplen;        /* max length of captured packets */
 
35
    uint32_t network;        /* data link type */
 
36
};
 
37
BUILD_ASSERT_DECL(sizeof(struct pcap_hdr) == 24);
 
38
 
 
39
struct pcaprec_hdr {
 
40
    uint32_t ts_sec;         /* timestamp seconds */
 
41
    uint32_t ts_usec;        /* timestamp microseconds */
 
42
    uint32_t incl_len;       /* number of octets of packet saved in file */
 
43
    uint32_t orig_len;       /* actual length of packet */
 
44
};
 
45
BUILD_ASSERT_DECL(sizeof(struct pcaprec_hdr) == 16);
 
46
 
 
47
FILE *
 
48
pcap_open(const char *file_name, const char *mode)
 
49
{
 
50
    FILE *file;
 
51
 
 
52
    ovs_assert(!strcmp(mode, "rb") || !strcmp(mode, "wb"));
 
53
 
 
54
    file = fopen(file_name, mode);
 
55
    if (file == NULL) {
 
56
        VLOG_WARN("%s: failed to open pcap file for %s",
 
57
                  file_name, mode[0] == 'r' ? "reading" : "writing");
 
58
        return NULL;
 
59
    }
 
60
 
 
61
    if (mode[0] == 'r') {
 
62
        if (!pcap_read_header(file)) {
 
63
            fclose(file);
 
64
            return NULL;
 
65
        }
 
66
    } else {
 
67
        pcap_write_header(file);
 
68
    }
 
69
    return file;
 
70
}
 
71
 
 
72
int
 
73
pcap_read_header(FILE *file)
 
74
{
 
75
    struct pcap_hdr ph;
 
76
    if (fread(&ph, sizeof ph, 1, file) != 1) {
 
77
        int error = ferror(file) ? errno : EOF;
 
78
        VLOG_WARN("failed to read pcap header: %s", ovs_retval_to_string(error));
 
79
        return error;
 
80
    }
 
81
    if (ph.magic_number != 0xa1b2c3d4 && ph.magic_number != 0xd4c3b2a1) {
 
82
        VLOG_WARN("bad magic 0x%08"PRIx32" reading pcap file "
 
83
                  "(expected 0xa1b2c3d4 or 0xd4c3b2a1)", ph.magic_number);
 
84
        return EPROTO;
 
85
    }
 
86
    return 0;
 
87
}
 
88
 
 
89
void
 
90
pcap_write_header(FILE *file)
 
91
{
 
92
    /* The pcap reader is responsible for figuring out endianness based on the
 
93
     * magic number, so the lack of htonX calls here is intentional. */
 
94
    struct pcap_hdr ph;
 
95
    ph.magic_number = 0xa1b2c3d4;
 
96
    ph.version_major = 2;
 
97
    ph.version_minor = 4;
 
98
    ph.thiszone = 0;
 
99
    ph.sigfigs = 0;
 
100
    ph.snaplen = 1518;
 
101
    ph.network = 1;             /* Ethernet */
 
102
    ignore(fwrite(&ph, sizeof ph, 1, file));
 
103
}
 
104
 
 
105
int
 
106
pcap_read(FILE *file, struct ofpbuf **bufp)
 
107
{
 
108
    struct pcaprec_hdr prh;
 
109
    struct ofpbuf *buf;
 
110
    void *data;
 
111
    size_t len;
 
112
 
 
113
    *bufp = NULL;
 
114
 
 
115
    /* Read header. */
 
116
    if (fread(&prh, sizeof prh, 1, file) != 1) {
 
117
        int error = ferror(file) ? errno : EOF;
 
118
        VLOG_WARN("failed to read pcap record header: %s",
 
119
                  ovs_retval_to_string(error));
 
120
        return error;
 
121
    }
 
122
 
 
123
    /* Calculate length. */
 
124
    len = prh.incl_len;
 
125
    if (len > 0xffff) {
 
126
        uint32_t swapped_len = (((len & 0xff000000) >> 24) |
 
127
                                ((len & 0x00ff0000) >>  8) |
 
128
                                ((len & 0x0000ff00) <<  8) |
 
129
                                ((len & 0x000000ff) << 24));
 
130
        if (swapped_len > 0xffff) {
 
131
            VLOG_WARN("bad packet length %zu or %"PRIu32" "
 
132
                      "reading pcap file",
 
133
                      len, swapped_len);
 
134
            return EPROTO;
 
135
        }
 
136
        len = swapped_len;
 
137
    }
 
138
 
 
139
    /* Read packet. */
 
140
    buf = ofpbuf_new(len);
 
141
    data = ofpbuf_put_uninit(buf, len);
 
142
    if (fread(data, len, 1, file) != 1) {
 
143
        int error = ferror(file) ? errno : EOF;
 
144
        VLOG_WARN("failed to read pcap packet: %s",
 
145
                  ovs_retval_to_string(error));
 
146
        ofpbuf_delete(buf);
 
147
        return error;
 
148
    }
 
149
    *bufp = buf;
 
150
    return 0;
 
151
}
 
152
 
 
153
void
 
154
pcap_write(FILE *file, struct ofpbuf *buf)
 
155
{
 
156
    struct pcaprec_hdr prh;
 
157
    prh.ts_sec = 0;
 
158
    prh.ts_usec = 0;
 
159
    prh.incl_len = buf->size;
 
160
    prh.orig_len = buf->size;
 
161
    ignore(fwrite(&prh, sizeof prh, 1, file));
 
162
    ignore(fwrite(buf->data, buf->size, 1, file));
 
163
}