Add UDT dissector. Bug 8741 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id...
[metze/wireshark/wip.git] / capture_wpcap_packet.c
1 /* capture_wpcap_packet.c
2  * WinPcap-specific interfaces for low-level information (packet.dll).
3  * We load WinPcap at run
4  * time, so that we only need one Wireshark binary and one TShark binary
5  * for Windows, regardless of whether WinPcap is installed or not.
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 2001 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #if defined HAVE_LIBPCAP && defined _WIN32
31
32 #include <glib.h>
33 #include <gmodule.h>
34
35 #include <pcap.h>
36
37 /* XXX - yes, I know, I should move cppmagic.h to a generic location. */
38 #include "tools/lemon/cppmagic.h"
39
40 #include <epan/value_string.h>
41
42 #include <winsock2.h>    /* Needed here to force a definition of WINVER           */
43                          /* for some (all ?) Microsoft compilers newer than vc6.  */
44                          /* (If windows.h were used instead, there might be       */
45                          /*  issues re winsock.h included before winsock2.h )     */
46 #include <windowsx.h>
47 #include <Ntddndis.h>
48
49 #include "capture_wpcap_packet.h"
50 #include <wsutil/file_util.h>
51
52 /* packet32.h requires sockaddr_storage
53  * whether sockaddr_storage is defined or not depends on the Platform SDK
54  * version installed. The only one not defining it is the SDK that comes
55  * with MSVC 6.0 (WINVER 0x0400).
56  *
57  * copied from RFC2553 (and slightly modified because of datatypes) ...
58  * XXX - defined more than once, move this to a header file */
59 #ifndef WINVER
60 #error WINVER not defined ....
61 #endif
62 #if (WINVER <= 0x0400) && defined(_MSC_VER)
63 typedef unsigned short eth_sa_family_t;
64
65 /*
66  * Desired design of maximum size and alignment
67  */
68 #define ETH_SS_MAXSIZE    128  /* Implementation specific max size */
69 #define ETH_SS_ALIGNSIZE  (sizeof (gint64 /*int64_t*/))
70                          /* Implementation specific desired alignment */
71 /*
72  * Definitions used for sockaddr_storage structure paddings design.
73  */
74 #define ETH_SS_PAD1SIZE   (ETH_SS_ALIGNSIZE - sizeof (eth_sa_family_t))
75 #define ETH_SS_PAD2SIZE   (ETH_SS_MAXSIZE - (sizeof (eth_sa_family_t) + \
76                               ETH_SS_PAD1SIZE + ETH_SS_ALIGNSIZE))
77
78 struct sockaddr_storage {
79     eth_sa_family_t  __ss_family;     /* address family */
80     /* Following fields are implementation specific */
81     char      __ss_pad1[ETH_SS_PAD1SIZE];
82               /* 6 byte pad, this is to make implementation */
83               /* specific pad up to alignment field that */
84               /* follows explicit in the data structure */
85     gint64 /*int64_t*/   __ss_align;     /* field to force desired structure */
86                /* storage alignment */
87     char      __ss_pad2[ETH_SS_PAD2SIZE];
88               /* 112 byte pad to achieve desired size, */
89               /* _SS_MAXSIZE value minus size of ss_family */
90               /* __ss_pad1, __ss_align fields is 112 */
91 };
92 /* ... copied from RFC2553 */
93 #endif /* WINVER */
94
95 #include <Packet32.h>
96
97 gboolean has_wpacket = FALSE;
98
99
100 /* This module will use the PacketRequest function in packet.dll (coming with WinPcap) to "directly" access
101  * the Win32 NDIS network driver(s) and ask for various values (status, statistics, ...).
102  *
103  * Unfortunately, the definitions required for this are not available through the usual windows header files,
104  * but require the Windows "Device Driver Kit" which is not available for free :-(
105  *
106  * Fortunately, the definitions needed to access the various NDIS values are available from various OSS projects:
107  * - WinPcap in Ntddndis.h
108  * - Ndiswrapper in driver/ndis.h and driver/iw_ndis.h
109  * - cygwin (MingW?) in usr/include/w32api/ddk/ndis.h and ntddndis.h
110  * - FreeBSD (netperf)
111  */
112
113 /* The MSDN description of the NDIS driver API is available at:
114 /* MSDN Home >  MSDN Library >  Win32 and COM Development >  Driver Development Kit >  Network Devices and Protocols >  Reference */
115 /* "NDIS Objects" */
116 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/network/hh/network/21oidovw_d55042e5-0b8a-4439-8ef2-be7331e98464.xml.asp */
117
118 /* Some more interesting links:
119  * http://sourceforge.net/projects/ndiswrapper/
120  * http://www.osronline.com/lists_archive/windbg/thread521.html
121  * http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ndis.h?view=markup
122  * http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddndis.h?view=markup
123  */
124
125
126
127 /******************************************************************************************************************************/
128 /* stuff to load WinPcap's packet.dll and the functions required from it */
129
130 static PCHAR     (*p_PacketGetVersion) (void);
131 static LPADAPTER (*p_PacketOpenAdapter) (char *adaptername);
132 static void      (*p_PacketCloseAdapter) (LPADAPTER);
133 static int       (*p_PacketRequest) (LPADAPTER, int, void *);
134
135 typedef struct {
136     const char  *name;
137     gpointer    *ptr;
138     gboolean    optional;
139 } symbol_table_t;
140
141 #define SYM(x, y)   { STRINGIFY(x) , (gpointer) &CONCAT(p_,x), y }
142
143 void
144 wpcap_packet_load(void)
145 {
146
147     /* These are the symbols I need or want from packet.dll */
148     static const symbol_table_t symbols[] = {
149         SYM(PacketGetVersion, FALSE),
150         SYM(PacketOpenAdapter, FALSE),
151         SYM(PacketCloseAdapter, FALSE),
152         SYM(PacketRequest, FALSE),
153         { NULL, NULL, FALSE }
154     };
155
156     GModule     *wh; /* wpcap handle */
157     const symbol_table_t    *sym;
158
159     wh = ws_module_open("packet.dll", 0);
160
161     if (!wh) {
162         return;
163     }
164
165     sym = symbols;
166     while (sym->name) {
167         if (!g_module_symbol(wh, sym->name, sym->ptr)) {
168             if (sym->optional) {
169                 /*
170                  * We don't care if it's missing; we just
171                  * don't use it.
172                  */
173                 *sym->ptr = NULL;
174             } else {
175                 /*
176                  * We require this symbol.
177                  */
178                 return;
179             }
180         }
181         sym++;
182     }
183
184     has_wpacket = TRUE;
185 }
186
187
188
189 /******************************************************************************************************************************/
190 /* functions to access the NDIS driver values */
191
192
193 /* get dll version */
194 char *
195 wpcap_packet_get_version(void)
196 {
197     if(!has_wpacket) {
198         return NULL;
199     }
200     return p_PacketGetVersion();
201 }
202
203
204 /* open the interface */
205 void *
206 wpcap_packet_open(char *if_name)
207 {
208     LPADAPTER   adapter;
209
210     g_assert(has_wpacket);
211     adapter = p_PacketOpenAdapter(if_name);
212
213     return adapter;
214 }
215
216
217 /* close the interface */
218 void
219 wpcap_packet_close(void *adapter)
220 {
221
222     g_assert(has_wpacket);
223     p_PacketCloseAdapter(adapter);
224 }
225
226
227 /* do a packet request call */
228 int
229 wpcap_packet_request(void *adapter, ULONG Oid, int set, char *value, unsigned int *length)
230 {
231     BOOLEAN    Status;
232     ULONG      IoCtlBufferLength=(sizeof(PACKET_OID_DATA) + (*length) - 1);
233     PPACKET_OID_DATA  OidData;
234
235
236     g_assert(has_wpacket);
237
238     if(p_PacketRequest == NULL) {
239         g_warning("packet_request not available\n");
240         return 0;
241     }
242
243     /* get a buffer suitable for PacketRequest() */
244     OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
245     if (OidData == NULL) {
246         g_warning("GlobalAllocPtr failed for %u\n", IoCtlBufferLength);
247         return 0;
248     }
249
250     OidData->Oid = Oid;
251     OidData->Length = *length;
252     memcpy(OidData->Data, value, *length);
253
254     Status = p_PacketRequest(adapter, set, OidData);
255
256     if(Status) {
257         if(OidData->Length <= *length) {
258             /* copy value from driver */
259             memcpy(value, OidData->Data, OidData->Length);
260             *length = OidData->Length;
261         } else {
262             /* the driver returned a value that is longer than expected (and longer than the given buffer) */
263             g_warning("returned oid too long, Oid: 0x%x OidLen:%u MaxLen:%u", Oid, OidData->Length, *length);
264             Status = FALSE;
265         }
266     }
267
268     GlobalFreePtr (OidData);
269
270     if(Status) {
271         return 1;
272     } else {
273         return 0;
274     }
275 }
276
277
278 /* get an UINT value using the packet request call */
279 int
280 wpcap_packet_request_uint(void *adapter, ULONG Oid, UINT *value)
281 {
282     BOOLEAN     Status;
283     int         length = sizeof(UINT);
284
285
286     Status = wpcap_packet_request(adapter, Oid, FALSE /* !set */, (char *) value, &length);
287     if(Status && length == sizeof(UINT)) {
288         return 1;
289     } else {
290         return 0;
291     }
292 }
293
294
295 /* get an ULONG value using the NDIS packet request call */
296 int
297 wpcap_packet_request_ulong(void *adapter, ULONG Oid, ULONG *value)
298 {
299     BOOLEAN     Status;
300     int         length = sizeof(ULONG);
301
302
303     Status = wpcap_packet_request(adapter, Oid, FALSE /* !set */, (char *) value, &length);
304     if(Status && length == sizeof(ULONG)) {
305         return 1;
306     } else {
307         return 0;
308     }
309 }
310
311
312 #else /* HAVE_LIBPCAP && _WIN32 */
313
314 void
315 wpcap_packet_load(void)
316 {
317     return;
318 }
319
320 #endif /* HAVE_LIBPCAP */
321
322 /*
323  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
324  *
325  * Local variables:
326  * c-basic-offset: 4
327  * tab-width: 8
328  * indent-tabs-mode: nil
329  * End:
330  *
331  * ex: set shiftwidth=4 tabstop=8 expandtab:
332  * :indentSize=4:tabSize=8:noTabs=true:
333  */