]> The Tcpdump Group git mirrors - tcpdump/blob - netdissect.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / netdissect.c
1 /*
2 * Copyright (c) 1988-1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Copyright (c) 1998-2012 Michael Richardson <mcr@tcpdump.org>
6 * The TCPDUMP project
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that: (1) source code distributions
10 * retain the above copyright notice and this paragraph in its entirety, (2)
11 * distributions including binary code include the above copyright notice and
12 * this paragraph in its entirety in the documentation or other materials
13 * provided with the distribution, and (3) all advertising materials mentioning
14 * features or use of this software display the following acknowledgement:
15 * ``This product includes software developed by the University of California,
16 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17 * the University nor the names of its contributors may be used to endorse
18 * or promote products derived from this software without specific prior
19 * written permission.
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 */
24
25 #include <config.h>
26
27 #include "netdissect-stdinc.h"
28 #include "netdissect.h"
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #ifdef USE_LIBSMI
34 #include <smi.h>
35 #endif
36
37 #ifdef _AIX
38 #include "diag-control.h"
39 #endif /* _AIX */
40
41 /*
42 * Initialize anything that must be initialized before dissecting
43 * packets.
44 *
45 * This should be called at the beginning of the program; it does
46 * not need to be called, and should not be called, for every
47 * netdissect_options structure.
48 */
49 int
50 nd_init(char *errbuf, size_t errbuf_size)
51 {
52 #ifdef _WIN32
53 WORD wVersionRequested;
54 WSADATA wsaData;
55 int err;
56
57 /*
58 * Request Winsock 2.2; we expect Winsock 2.
59 */
60 wVersionRequested = MAKEWORD(2, 2);
61 err = WSAStartup(wVersionRequested, &wsaData);
62 if (err != 0) {
63 strlcpy(errbuf, "Attempting to initialize Winsock failed",
64 errbuf_size);
65 return (-1);
66 }
67 #endif /* _WIN32 */
68
69 #ifdef USE_LIBSMI
70 /*
71 * XXX - should we just fail if this fails? Some of the
72 * libsmi calls may fail.
73 */
74 smiInit("tcpdump");
75 #endif
76
77 /*
78 * Clears the error buffer, and uses it so we don't get
79 * "unused argument" warnings at compile time.
80 */
81 strlcpy(errbuf, "", errbuf_size);
82 return (0);
83 }
84
85 /*
86 * Clean up anything that nd_init() did.
87 */
88 void
89 nd_cleanup(void)
90 {
91 #ifdef USE_LIBSMI
92 /*
93 * This appears, in libsmi 0.4.8, to do nothing if smiInit()
94 * wasn't done or failed, so we call it unconditionally.
95 */
96 smiExit();
97 #endif
98
99 #ifdef _WIN32
100 /*
101 * Undo the WSAStartup() call above.
102 */
103 WSACleanup();
104 #endif
105 }
106
107 int
108 nd_have_smi_support(void)
109 {
110 #ifdef USE_LIBSMI
111 return (1);
112 #else
113 return (0);
114 #endif
115 }
116
117 /*
118 * Indicates whether an SMI module has been loaded, so that we can use
119 * libsmi to translate OIDs.
120 */
121 int nd_smi_module_loaded;
122
123 int
124 nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size)
125 {
126 #ifdef USE_LIBSMI
127 if (smiLoadModule(module) == 0) {
128 snprintf(errbuf, errbuf_size, "could not load MIB module %s",
129 module);
130 return (-1);
131 }
132 nd_smi_module_loaded = 1;
133 return (0);
134 #else
135 snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support",
136 module);
137 return (-1);
138 #endif
139 }
140
141 const char *
142 nd_smi_version_string(void)
143 {
144 #ifdef USE_LIBSMI
145 return (smi_version_string);
146 #else
147 return (NULL);
148 #endif
149 }
150
151
152 int
153 nd_push_buffer(netdissect_options *ndo, u_char *new_buffer,
154 const u_char *new_packetp, const u_int newlen)
155 {
156 struct netdissect_saved_packet_info *ndspi;
157
158 ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
159 if (ndspi == NULL)
160 return (0); /* fail */
161 ndspi->ndspi_buffer = new_buffer;
162 ndspi->ndspi_packetp = ndo->ndo_packetp;
163 ndspi->ndspi_snapend = ndo->ndo_snapend;
164 ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
165
166 ndo->ndo_packetp = new_packetp;
167 ndo->ndo_snapend = new_packetp + newlen;
168 ndo->ndo_packet_info_stack = ndspi;
169
170 return (1); /* success */
171 }
172
173
174 /*
175 * In a given netdissect_options structure:
176 *
177 * push the current packet information onto the packet information
178 * stack;
179 *
180 * given a pointer into the packet and a length past that point in
181 * the packet, calculate a new snapshot end that's at the lower
182 * of the current snapshot end and that point in the packet;
183 *
184 * set the snapshot end to that new value.
185 */
186 int
187 nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
188 {
189 struct netdissect_saved_packet_info *ndspi;
190 u_int snaplen_remaining;
191
192 ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
193 if (ndspi == NULL)
194 return (0); /* fail */
195 ndspi->ndspi_buffer = NULL; /* no new buffer */
196 ndspi->ndspi_packetp = ndo->ndo_packetp;
197 ndspi->ndspi_snapend = ndo->ndo_snapend;
198 ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
199
200 /*
201 * Push the saved previous data onto the stack.
202 */
203 ndo->ndo_packet_info_stack = ndspi;
204
205 /*
206 * Find out how many bytes remain after the current snapend.
207 *
208 * We're restricted to packets with at most UINT_MAX bytes;
209 * cast the result to u_int, so that we don't get truncation
210 * warnings on LP64 and LLP64 platforms. (ptrdiff_t is
211 * signed and we want an unsigned difference; the pointer
212 * should at most be equal to snapend, and must *never*
213 * be past snapend.)
214 */
215 snaplen_remaining = (u_int)(ndo->ndo_snapend - bp);
216
217 /*
218 * If the new snapend is smaller than the one calculated
219 * above, set the snapend to that value, otherwise leave
220 * it unchanged.
221 */
222 if (newlen <= snaplen_remaining) {
223 /* Snapend isn't past the previous snapend */
224 ndo->ndo_snapend = bp + newlen;
225 }
226
227 return (1); /* success */
228 }
229
230 /*
231 * In a given netdissect_options structure:
232 *
233 * given a pointer into the packet and a length past that point in
234 * the packet, calculate a new snapshot end that's at the lower
235 * of the previous snapshot end - or, if there is no previous
236 * snapshot end, the current snapshot end - and that point in the
237 * packet;
238 *
239 * set the snapshot end to that new value.
240 *
241 * This is to change the current snapshot end. This may increase the
242 * snapshot end, as it may be used, for example, for a Jumbo Payload
243 * option in IPv6. It must not increase it past the snapshot length
244 * atop which the current one was pushed, however.
245 */
246 void
247 nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
248 {
249 struct netdissect_saved_packet_info *ndspi;
250 const u_char *previous_snapend;
251 u_int snaplen_remaining;
252
253 ndspi = ndo->ndo_packet_info_stack;
254 if (ndspi->ndspi_prev != NULL)
255 previous_snapend = ndspi->ndspi_prev->ndspi_snapend;
256 else
257 previous_snapend = ndo->ndo_snapend;
258
259 /*
260 * Find out how many bytes remain after the previous
261 * snapend - or, if there is no previous snapend, after
262 * the current snapend.
263 *
264 * We're restricted to packets with at most UINT_MAX bytes;
265 * cast the result to u_int, so that we don't get truncation
266 * warnings on LP64 and LLP64 platforms. (ptrdiff_t is
267 * signed and we want an unsigned difference; the pointer
268 * should at most be equal to snapend, and must *never*
269 * be past snapend.)
270 */
271 snaplen_remaining = (u_int)(previous_snapend - bp);
272
273 /*
274 * If the new snapend is smaller than the one calculated
275 * above, set the snapend to that value, otherwise leave
276 * it unchanged.
277 */
278 if (newlen <= snaplen_remaining) {
279 /* Snapend isn't past the previous snapend */
280 ndo->ndo_snapend = bp + newlen;
281 }
282 }
283
284 void
285 nd_pop_packet_info(netdissect_options *ndo)
286 {
287 struct netdissect_saved_packet_info *ndspi;
288
289 ndspi = ndo->ndo_packet_info_stack;
290 ndo->ndo_packetp = ndspi->ndspi_packetp;
291 ndo->ndo_snapend = ndspi->ndspi_snapend;
292 ndo->ndo_packet_info_stack = ndspi->ndspi_prev;
293
294 free(ndspi->ndspi_buffer);
295 free(ndspi);
296 }
297
298 void
299 nd_pop_all_packet_info(netdissect_options *ndo)
300 {
301 while (ndo->ndo_packet_info_stack != NULL)
302 nd_pop_packet_info(ndo);
303 }
304
305 NORETURN void
306 nd_trunc_longjmp(netdissect_options *ndo)
307 {
308 longjmp(ndo->ndo_early_end, ND_TRUNCATED);
309 #ifdef _AIX
310 /*
311 * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells
312 * XL C that the function is noreturn, but GCC remains unaware of that and
313 * yields a "'noreturn' function does return" warning.
314 */
315 ND_NOT_REACHABLE
316 #endif /* _AIX */
317 }