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#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include "netdissect-stdinc.h"
30#include "netdissect.h"
31#include <string.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#ifdef USE_LIBSMI
36#include <smi.h>
37#endif
38
39/*
40 * Initialize anything that must be initialized before dissecting
41 * packets.
42 *
43 * This should be called at the beginning of the program; it does
44 * not need to be called, and should not be called, for every
45 * netdissect_options structure.
46 */
47int
48nd_init(char *errbuf, size_t errbuf_size)
49{
50#ifdef _WIN32
51	WORD wVersionRequested;
52	WSADATA wsaData;
53	int err;
54
55	/*
56	 * Request Winsock 2.2; we expect Winsock 2.
57	 */
58	wVersionRequested = MAKEWORD(2, 2);
59	err = WSAStartup(wVersionRequested, &wsaData);
60	if (err != 0) {
61		strlcpy(errbuf, "Attempting to initialize Winsock failed",
62		    errbuf_size);
63		return (-1);
64	}
65#endif /* _WIN32 */
66
67#ifdef USE_LIBSMI
68	/*
69	 * XXX - should we just fail if this fails?  Some of the
70	 * libsmi calls may fail.
71	 */
72	smiInit("tcpdump");
73#endif
74
75	/*
76	 * Clears the error buffer, and uses it so we don't get
77	 * "unused argument" warnings at compile time.
78	 */
79	strlcpy(errbuf, "", errbuf_size);
80	return (0);
81}
82
83/*
84 * Clean up anything that ndo_init() did.
85 */
86void
87nd_cleanup(void)
88{
89#ifdef USE_LIBSMI
90	/*
91	 * This appears, in libsmi 0.4.8, to do nothing if smiInit()
92	 * wasn't done or failed, so we call it unconditionally.
93	 */
94	smiExit();
95#endif
96
97#ifdef _WIN32
98	/*
99	 * Undo the WSAStartup() call above.
100	 */
101	WSACleanup();
102#endif
103}
104
105int
106nd_have_smi_support(void)
107{
108#ifdef USE_LIBSMI
109	return (1);
110#else
111	return (0);
112#endif
113}
114
115/*
116 * Indicates whether an SMI module has been loaded, so that we can use
117 * libsmi to translate OIDs.
118 */
119int nd_smi_module_loaded;
120
121int
122nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size)
123{
124#ifdef USE_LIBSMI
125	if (smiLoadModule(module) == 0) {
126		snprintf(errbuf, errbuf_size, "could not load MIB module %s",
127		    module);
128		return (-1);
129	}
130	nd_smi_module_loaded = 1;
131	return (0);
132#else
133	snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support",
134	    module);
135	return (-1);
136#endif
137}
138
139const char *
140nd_smi_version_string(void)
141{
142#ifdef USE_LIBSMI
143	return (smi_version_string);
144#else
145	return (NULL);
146#endif
147}
148
149
150int
151nd_push_buffer(netdissect_options *ndo, u_char *new_buffer,
152	       const u_char *new_packetp, const u_int newlen)
153{
154	struct netdissect_saved_packet_info *ndspi;
155
156	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
157	if (ndspi == NULL)
158		return (0);	/* fail */
159	ndspi->ndspi_buffer = new_buffer;
160	ndspi->ndspi_packetp = ndo->ndo_packetp;
161	ndspi->ndspi_snapend = ndo->ndo_snapend;
162	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
163
164	ndo->ndo_packetp = new_packetp;
165	ndo->ndo_snapend = new_packetp + newlen;
166	ndo->ndo_packet_info_stack = ndspi;
167
168	return (1);	/* success */
169}
170
171
172/*
173 * In a given netdissect_options structure:
174 *
175 *    push the current packet information onto the packet information
176 *    stack;
177 *
178 *    given a pointer into the packet and a length past that point in
179 *    the packet, calculate a new snapshot end that's at the lower
180 *    of the current snapshot end and that point in the packet;
181 *
182 *    set the snapshot end to that new value.
183 */
184int
185nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
186{
187	struct netdissect_saved_packet_info *ndspi;
188	u_int snaplen_remaining;
189
190	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
191	if (ndspi == NULL)
192		return (0);	/* fail */
193	ndspi->ndspi_buffer = NULL;	/* no new buffer */
194	ndspi->ndspi_packetp = ndo->ndo_packetp;
195	ndspi->ndspi_snapend = ndo->ndo_snapend;
196	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
197
198	/*
199	 * Push the saved previous data onto the stack.
200	 */
201	ndo->ndo_packet_info_stack = ndspi;
202
203	/*
204	 * Find out how many bytes remain after the current snapend.
205	 *
206	 * We're restricted to packets with at most UINT_MAX bytes;
207	 * cast the result to u_int, so that we don't get truncation
208	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
209	 * signed and we want an unsigned difference; the pointer
210	 * should at most be equal to snapend, and must *never*
211	 * be past snapend.)
212	 */
213	snaplen_remaining = (u_int)(ndo->ndo_snapend - bp);
214
215	/*
216	 * If the new snapend is smaller than the one calculated
217	 * above, set the snapend to that value, otherwise leave
218	 * it unchanged.
219	 */
220	if (newlen <= snaplen_remaining) {
221		/* Snapend isn't past the previous snapend */
222		ndo->ndo_snapend = bp + newlen;
223	}
224
225	return (1);	/* success */
226}
227
228/*
229 * In a given netdissect_options structure:
230 *
231 *    given a pointer into the packet and a length past that point in
232 *    the packet, calculate a new snapshot end that's at the lower
233 *    of the previous snapshot end - or, if there is no previous
234 *    snapshot end, the current snapshot end - and that point in the
235 *    packet;
236 *
237 *    set the snapshot end to that new value.
238 *
239 * This is to change the current snapshot end.  This may increase the
240 * snapshot end, as it may be used, for example, for a Jumbo Payload
241 * option in IPv6.  It must not increase it past the snapshot length
242 * atop which the current one was pushed, however.
243 */
244void
245nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
246{
247	struct netdissect_saved_packet_info *ndspi;
248	const u_char *previous_snapend;
249	u_int snaplen_remaining;
250
251	ndspi = ndo->ndo_packet_info_stack;
252	if (ndspi->ndspi_prev != NULL)
253		previous_snapend = ndspi->ndspi_prev->ndspi_snapend;
254	else
255		previous_snapend = ndo->ndo_snapend;
256
257	/*
258	 * Find out how many bytes remain after the previous
259	 * snapend - or, if there is no previous snapend, after
260	 * the current snapend.
261	 *
262	 * We're restricted to packets with at most UINT_MAX bytes;
263	 * cast the result to u_int, so that we don't get truncation
264	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
265	 * signed and we want an unsigned difference; the pointer
266	 * should at most be equal to snapend, and must *never*
267	 * be past snapend.)
268	 */
269	snaplen_remaining = (u_int)(previous_snapend - bp);
270
271	/*
272	 * If the new snapend is smaller than the one calculated
273	 * above, set the snapend to that value, otherwise leave
274	 * it unchanged.
275	 */
276	if (newlen <= snaplen_remaining) {
277		/* Snapend isn't past the previous snapend */
278		ndo->ndo_snapend = bp + newlen;
279	}
280}
281
282void
283nd_pop_packet_info(netdissect_options *ndo)
284{
285	struct netdissect_saved_packet_info *ndspi;
286
287	ndspi = ndo->ndo_packet_info_stack;
288	ndo->ndo_packetp = ndspi->ndspi_packetp;
289	ndo->ndo_snapend = ndspi->ndspi_snapend;
290	ndo->ndo_packet_info_stack = ndspi->ndspi_prev;
291
292	free(ndspi->ndspi_buffer);
293	free(ndspi);
294}
295
296void
297nd_pop_all_packet_info(netdissect_options *ndo)
298{
299	while (ndo->ndo_packet_info_stack != NULL)
300		nd_pop_packet_info(ndo);
301}
302