]> The Tcpdump Group git mirrors - libpcap/blob - fad-win32.c
Give it an SCCS and RCS ID.
[libpcap] / fad-win32.c
1 /*
2 * Copyright (c) 1999, 2002
3 * Politecnico di Torino. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #ifndef lint
23 static const char rcsid[] =
24 "@(#) $Header: /tcpdump/master/libpcap/fad-win32.c,v 1.4 2002-08-08 09:15:57 guy Exp $ (LBL)";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <pcap.h>
32 #include <packet32.h>
33
34 #include <errno.h>
35
36 #ifndef SA_LEN
37 #ifdef HAVE_SOCKADDR_SA_LEN
38 #define SA_LEN(addr) ((addr)->sa_len)
39 #else /* HAVE_SOCKADDR_SA_LEN */
40 #define SA_LEN(addr) (sizeof (struct sockaddr))
41 #endif /* HAVE_SOCKADDR_SA_LEN */
42 #endif /* SA_LEN */
43
44 /*
45 * Add an entry to the list of addresses for an interface.
46 * "curdev" is the entry for that interface.
47 */
48 static int
49 add_addr_to_list(pcap_if_t *curdev, struct sockaddr *addr,
50 struct sockaddr *netmask, struct sockaddr *broadaddr,
51 struct sockaddr *dstaddr, char *errbuf)
52 {
53 pcap_addr_t *curaddr, *prevaddr, *nextaddr;
54
55 /*
56 * Allocate the new entry and fill it in.
57 */
58 curaddr = (pcap_addr_t*)malloc(sizeof(pcap_addr_t));
59 if (curaddr == NULL) {
60 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
61 "malloc: %s", pcap_strerror(errno));
62 return (-1);
63 }
64
65 curaddr->next = NULL;
66 if (addr != NULL) {
67 curaddr->addr = (struct sockaddr*)dup_sockaddr(addr, SA_LEN(addr));
68 if (curaddr->addr == NULL) {
69 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
70 "malloc: %s", pcap_strerror(errno));
71 free(curaddr);
72 return (-1);
73 }
74 } else
75 curaddr->addr = NULL;
76
77 if (netmask != NULL) {
78 curaddr->netmask = (struct sockaddr*)dup_sockaddr(netmask, SA_LEN(netmask));
79 if (curaddr->netmask == NULL) {
80 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
81 "malloc: %s", pcap_strerror(errno));
82 free(curaddr);
83 return (-1);
84 }
85 } else
86 curaddr->netmask = NULL;
87
88 if (broadaddr != NULL) {
89 curaddr->broadaddr = (struct sockaddr*)dup_sockaddr(broadaddr, SA_LEN(broadaddr));
90 if (curaddr->broadaddr == NULL) {
91 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
92 "malloc: %s", pcap_strerror(errno));
93 free(curaddr);
94 return (-1);
95 }
96 } else
97 curaddr->broadaddr = NULL;
98
99 if (dstaddr != NULL) {
100 curaddr->dstaddr = (struct sockaddr*)dup_sockaddr(dstaddr, SA_LEN(dstaddr));
101 if (curaddr->dstaddr == NULL) {
102 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
103 "malloc: %s", pcap_strerror(errno));
104 free(curaddr);
105 return (-1);
106 }
107 } else
108 curaddr->dstaddr = NULL;
109
110 /*
111 * Find the end of the list of addresses.
112 */
113 for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
114 nextaddr = prevaddr->next;
115 if (nextaddr == NULL) {
116 /*
117 * This is the end of the list.
118 */
119 break;
120 }
121 }
122
123 if (prevaddr == NULL) {
124 /*
125 * The list was empty; this is the first member.
126 */
127 curdev->addresses = curaddr;
128 } else {
129 /*
130 * "prevaddr" is the last member of the list; append
131 * this member to it.
132 */
133 prevaddr->next = curaddr;
134 }
135
136 return (0);
137 }
138
139
140 static int
141 pcap_add_if_win32(pcap_if_t **devlist, char *name, const char *desc,
142 char *errbuf)
143 {
144 pcap_if_t *curdev;
145 npf_if_addr if_addrs[16];
146 LONG if_addr_size;
147 int res = 0;
148 struct sockaddr_in *addr, *netmask;
149
150 if_addr_size = 16;
151
152 /*
153 * Add an entry for this interface, with no addresses.
154 */
155 if (add_or_find_if(&curdev, devlist, (char *)name, 0, (char *)desc,
156 errbuf) == -1) {
157 /*
158 * Failure.
159 */
160 return (-1);
161 }
162
163 /*
164 * Get the list of addresses for the interface.
165 *
166 * XXX - what about IPv6?
167 */
168 if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) {
169 /*
170 * Failure.
171 *
172 * We don't return an error, because this can happen with
173 * NdisWan interfaces, and we want to supply them even
174 * if we can't supply their addresses.
175 *
176 * We return an entry with an empty address list.
177 */
178 return (0);
179 }
180
181 /*
182 * Now add the addresses.
183 */
184 while (if_addr_size-- > 0) {
185 /*
186 * "curdev" is an entry for this interface; add an entry for
187 * this address to its list of addresses.
188 */
189 if(curdev == NULL)
190 break;
191 res = add_addr_to_list(curdev,
192 (struct sockaddr *)&if_addrs[if_addr_size].IPAddress,
193 (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask,
194 (struct sockaddr *)&if_addrs[if_addr_size].Broadcast,
195 NULL,
196 errbuf);
197 if (res == -1) {
198 /*
199 * Failure.
200 */
201 break;
202 }
203 }
204
205 return (res);
206 }
207
208
209 /*
210 * Get a list of all interfaces that are up and that we can open.
211 * Returns -1 on error, 0 otherwise.
212 * The list, as returned through "alldevsp", may be null if no interfaces
213 * were up and could be opened.
214 *
215 * Win32 implementation, based on WinPcap
216 */
217 int
218 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
219 {
220 pcap_if_t *devlist = NULL;
221 DWORD dwVersion;
222 DWORD dwWindowsMajorVersion;
223 int ret = 0;
224 const char *desc;
225
226 dwVersion = GetVersion(); /* get the OS version */
227 dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
228 if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
229 /*
230 * Windows 95, 98, ME.
231 */
232 char AdaptersName[8192];
233 ULONG NameLength = 8192;
234 char *name;
235
236 if (!PacketGetAdapterNames(AdaptersName, &NameLength)) {
237 snprintf(errbuf, PCAP_ERRBUF_SIZE,
238 "PacketGetAdapterNames: %s",
239 pcap_win32strerror());
240 return (-1);
241 }
242
243 /*
244 * "PacketGetAdapterNames()" returned a list of
245 * null-terminated ASCII interface name strings,
246 * terminated by a null string, followed by a list
247 * of null-terminated ASCII interface description
248 * strings, terminated by a null string.
249 * This means there are two ASCII nulls at the end
250 * of the first list.
251 *
252 * Find the end of the first list; that's the
253 * beginning of the second list.
254 */
255 desc = &AdaptersName[0];
256 while (*desc != '\0' || *(desc + 1) != '\0')
257 desc++;
258
259 /*
260 * Found it - "desc" points to the first of the two
261 * nulls at the end of the list of names, so the
262 * first byte of the list of descriptions is two bytes
263 * after it.
264 */
265 desc += 2;
266
267 /*
268 * Loop over the elements in the first list.
269 */
270 name = &AdaptersName[0];
271 while (*name != '\0') {
272 /*
273 * Add an entry for this interface.
274 */
275 if (pcap_add_if_win32(&devlist, name, desc,
276 errbuf) == -1) {
277 /*
278 * Failure.
279 */
280 ret = -1;
281 break;
282 }
283 name += strlen(name) + 1;
284 desc += strlen(desc) + 1;
285 }
286 } else {
287 /*
288 * Windows NT (NT 4.0, W2K, WXP).
289 */
290 WCHAR AdaptersName[8192];
291 ULONG NameLength = 8192;
292 const WCHAR *t;
293 WCHAR *uc_name;
294 char ascii_name[8192];
295 char ascii_desc[8192];
296 char *p;
297
298 if (!PacketGetAdapterNames((PTSTR)AdaptersName, &NameLength)) {
299 snprintf(errbuf, PCAP_ERRBUF_SIZE,
300 "PacketGetAdapterNames: %s",
301 pcap_win32strerror());
302 return (-1);
303 }
304
305 /*
306 * "PacketGetAdapterNames()" returned a list of
307 * null-terminated Unicode interface name strings,
308 * terminated by a null string, followed by a list
309 * of null-terminated ASCII interface description
310 * strings, terminated by a null string.
311 * This means there are two Unicode nulls at the end
312 * of the first list.
313 *
314 * Find the end of the first list; that's the
315 * beginning of the second list.
316 */
317 t = &AdaptersName[0];
318 while (*t != '\0' || *(t + 1) != '\0')
319 t++;
320
321 /*
322 * Found it - "t" points to the first of the two
323 * nulls at the end of the list of names, so the
324 * first byte of the list of descriptions is two wide
325 * characters after it.
326 */
327 t += 2;
328 desc = (const char *)t;
329
330 /*
331 * Loop over the elements in the first list.
332 *
333 * We assume all characters in the name string are valid
334 * ASCII characters.
335 */
336 uc_name = &AdaptersName[0];
337 while (*uc_name != '\0') {
338 p = ascii_name;
339 while ((*p++ = (char)*uc_name++) != '\0')
340 ;
341 p = ascii_desc;
342 while ((*p++ = *desc++) != '\0')
343 ;
344
345 /*
346 * Add an entry for this interface.
347 */
348 if (pcap_add_if_win32(&devlist, ascii_name,
349 ascii_desc, errbuf) == -1) {
350 /*
351 * Failure.
352 */
353 ret = -1;
354 break;
355 }
356 }
357 }
358
359 if (ret == -1) {
360 /*
361 * We had an error; free the list we've been constructing.
362 */
363 if (devlist != NULL) {
364 pcap_freealldevs(devlist);
365 devlist = NULL;
366 }
367 }
368
369 *alldevsp = devlist;
370 return (ret);
371 }