]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
cb22974d | 2 | * Copyright (c) 2009, 2010, 2012 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
2c78a3e6 | 18 | #include "pcap-file.h" |
064af421 BP |
19 | #include <errno.h> |
20 | #include <inttypes.h> | |
21 | #include <string.h> | |
22 | #include "compiler.h" | |
23 | #include "ofpbuf.h" | |
064af421 BP |
24 | #include "vlog.h" |
25 | ||
d98e6007 | 26 | VLOG_DEFINE_THIS_MODULE(pcap); |
5136ce49 | 27 | |
064af421 BP |
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 */ | |
381328fe BP |
36 | }; |
37 | BUILD_ASSERT_DECL(sizeof(struct pcap_hdr) == 24); | |
064af421 BP |
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 */ | |
381328fe BP |
44 | }; |
45 | BUILD_ASSERT_DECL(sizeof(struct pcaprec_hdr) == 16); | |
064af421 BP |
46 | |
47 | FILE * | |
48 | pcap_open(const char *file_name, const char *mode) | |
49 | { | |
50 | FILE *file; | |
51 | ||
cb22974d | 52 | ovs_assert(!strcmp(mode, "rb") || !strcmp(mode, "wb")); |
064af421 BP |
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; | |
c18ea70d | 78 | VLOG_WARN("failed to read pcap header: %s", ovs_retval_to_string(error)); |
064af421 BP |
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 */ | |
b1b5cd8e | 102 | ignore(fwrite(&ph, sizeof ph, 1, file)); |
064af421 BP |
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", | |
c18ea70d | 119 | ovs_retval_to_string(error)); |
064af421 BP |
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) { | |
2886875a | 131 | VLOG_WARN("bad packet length %zu or %"PRIu32" " |
064af421 BP |
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", | |
c18ea70d | 145 | ovs_retval_to_string(error)); |
064af421 BP |
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; | |
b1b5cd8e AE |
161 | ignore(fwrite(&prh, sizeof prh, 1, file)); |
162 | ignore(fwrite(buf->data, buf->size, 1, file)); | |
064af421 | 163 | } |