]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
381328fe | 2 | * Copyright (c) 2009, 2010 Nicira Networks. |
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> | |
18 | #include "pcap.h" | |
19 | #include <assert.h> | |
20 | #include <errno.h> | |
21 | #include <inttypes.h> | |
22 | #include <string.h> | |
23 | #include "compiler.h" | |
24 | #include "ofpbuf.h" | |
064af421 BP |
25 | #include "vlog.h" |
26 | ||
5136ce49 BP |
27 | VLOG_DEFINE_THIS_MODULE(pcap) |
28 | ||
064af421 BP |
29 | struct pcap_hdr { |
30 | uint32_t magic_number; /* magic number */ | |
31 | uint16_t version_major; /* major version number */ | |
32 | uint16_t version_minor; /* minor version number */ | |
33 | int32_t thiszone; /* GMT to local correction */ | |
34 | uint32_t sigfigs; /* accuracy of timestamps */ | |
35 | uint32_t snaplen; /* max length of captured packets */ | |
36 | uint32_t network; /* data link type */ | |
381328fe BP |
37 | }; |
38 | BUILD_ASSERT_DECL(sizeof(struct pcap_hdr) == 24); | |
064af421 BP |
39 | |
40 | struct pcaprec_hdr { | |
41 | uint32_t ts_sec; /* timestamp seconds */ | |
42 | uint32_t ts_usec; /* timestamp microseconds */ | |
43 | uint32_t incl_len; /* number of octets of packet saved in file */ | |
44 | uint32_t orig_len; /* actual length of packet */ | |
381328fe BP |
45 | }; |
46 | BUILD_ASSERT_DECL(sizeof(struct pcaprec_hdr) == 16); | |
064af421 BP |
47 | |
48 | FILE * | |
49 | pcap_open(const char *file_name, const char *mode) | |
50 | { | |
51 | FILE *file; | |
52 | ||
53 | assert(!strcmp(mode, "rb") || !strcmp(mode, "wb")); | |
54 | ||
55 | file = fopen(file_name, mode); | |
56 | if (file == NULL) { | |
57 | VLOG_WARN("%s: failed to open pcap file for %s", | |
58 | file_name, mode[0] == 'r' ? "reading" : "writing"); | |
59 | return NULL; | |
60 | } | |
61 | ||
62 | if (mode[0] == 'r') { | |
63 | if (!pcap_read_header(file)) { | |
64 | fclose(file); | |
65 | return NULL; | |
66 | } | |
67 | } else { | |
68 | pcap_write_header(file); | |
69 | } | |
70 | return file; | |
71 | } | |
72 | ||
73 | int | |
74 | pcap_read_header(FILE *file) | |
75 | { | |
76 | struct pcap_hdr ph; | |
77 | if (fread(&ph, sizeof ph, 1, file) != 1) { | |
78 | int error = ferror(file) ? errno : EOF; | |
79 | VLOG_WARN("failed to read pcap header: %s", | |
80 | error > 0 ? strerror(error) : "end of file"); | |
81 | return error; | |
82 | } | |
83 | if (ph.magic_number != 0xa1b2c3d4 && ph.magic_number != 0xd4c3b2a1) { | |
84 | VLOG_WARN("bad magic 0x%08"PRIx32" reading pcap file " | |
85 | "(expected 0xa1b2c3d4 or 0xd4c3b2a1)", ph.magic_number); | |
86 | return EPROTO; | |
87 | } | |
88 | return 0; | |
89 | } | |
90 | ||
91 | void | |
92 | pcap_write_header(FILE *file) | |
93 | { | |
94 | /* The pcap reader is responsible for figuring out endianness based on the | |
95 | * magic number, so the lack of htonX calls here is intentional. */ | |
96 | struct pcap_hdr ph; | |
97 | ph.magic_number = 0xa1b2c3d4; | |
98 | ph.version_major = 2; | |
99 | ph.version_minor = 4; | |
100 | ph.thiszone = 0; | |
101 | ph.sigfigs = 0; | |
102 | ph.snaplen = 1518; | |
103 | ph.network = 1; /* Ethernet */ | |
104 | fwrite(&ph, sizeof ph, 1, file); | |
105 | } | |
106 | ||
107 | int | |
108 | pcap_read(FILE *file, struct ofpbuf **bufp) | |
109 | { | |
110 | struct pcaprec_hdr prh; | |
111 | struct ofpbuf *buf; | |
112 | void *data; | |
113 | size_t len; | |
114 | ||
115 | *bufp = NULL; | |
116 | ||
117 | /* Read header. */ | |
118 | if (fread(&prh, sizeof prh, 1, file) != 1) { | |
119 | int error = ferror(file) ? errno : EOF; | |
120 | VLOG_WARN("failed to read pcap record header: %s", | |
121 | error > 0 ? strerror(error) : "end of file"); | |
122 | return error; | |
123 | } | |
124 | ||
125 | /* Calculate length. */ | |
126 | len = prh.incl_len; | |
127 | if (len > 0xffff) { | |
128 | uint32_t swapped_len = (((len & 0xff000000) >> 24) | | |
129 | ((len & 0x00ff0000) >> 8) | | |
130 | ((len & 0x0000ff00) << 8) | | |
131 | ((len & 0x000000ff) << 24)); | |
132 | if (swapped_len > 0xffff) { | |
2886875a | 133 | VLOG_WARN("bad packet length %zu or %"PRIu32" " |
064af421 BP |
134 | "reading pcap file", |
135 | len, swapped_len); | |
136 | return EPROTO; | |
137 | } | |
138 | len = swapped_len; | |
139 | } | |
140 | ||
141 | /* Read packet. */ | |
142 | buf = ofpbuf_new(len); | |
143 | data = ofpbuf_put_uninit(buf, len); | |
144 | if (fread(data, len, 1, file) != 1) { | |
145 | int error = ferror(file) ? errno : EOF; | |
146 | VLOG_WARN("failed to read pcap packet: %s", | |
147 | error > 0 ? strerror(error) : "end of file"); | |
148 | ofpbuf_delete(buf); | |
149 | return error; | |
150 | } | |
151 | *bufp = buf; | |
152 | return 0; | |
153 | } | |
154 | ||
155 | void | |
156 | pcap_write(FILE *file, struct ofpbuf *buf) | |
157 | { | |
158 | struct pcaprec_hdr prh; | |
159 | prh.ts_sec = 0; | |
160 | prh.ts_usec = 0; | |
161 | prh.incl_len = buf->size; | |
162 | prh.orig_len = buf->size; | |
163 | fwrite(&prh, sizeof prh, 1, file); | |
164 | fwrite(buf->data, buf->size, 1, file); | |
165 | } |