1f0fdf33pst/*
2ca0d84cfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
3f0fdf33pst *	The Regents of the University of California.  All rights reserved.
4f0fdf33pst *
5f0fdf33pst * Redistribution and use in source and binary forms, with or without
6f0fdf33pst * modification, are permitted provided that the following conditions
7f0fdf33pst * are met:
8f0fdf33pst * 1. Redistributions of source code must retain the above copyright
9f0fdf33pst *    notice, this list of conditions and the following disclaimer.
10f0fdf33pst * 2. Redistributions in binary form must reproduce the above copyright
11f0fdf33pst *    notice, this list of conditions and the following disclaimer in the
12f0fdf33pst *    documentation and/or other materials provided with the distribution.
13f0fdf33pst * 3. All advertising materials mentioning features or use of this software
14f0fdf33pst *    must display the following acknowledgement:
15f0fdf33pst *	This product includes software developed by the Computer Systems
16f0fdf33pst *	Engineering Group at Lawrence Berkeley Laboratory.
17f0fdf33pst * 4. Neither the name of the University nor of the Laboratory may be used
18f0fdf33pst *    to endorse or promote products derived from this software without
19f0fdf33pst *    specific prior written permission.
20f0fdf33pst *
21f0fdf33pst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22f0fdf33pst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23f0fdf33pst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24f0fdf33pst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25f0fdf33pst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26f0fdf33pst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27f0fdf33pst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28f0fdf33pst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29f0fdf33pst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30f0fdf33pst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f0fdf33pst * SUCH DAMAGE.
32f0fdf33pst */
33f0fdf33pst
34a6bce88fenner#ifdef HAVE_CONFIG_H
3519bb0b8hselasky#include <config.h>
36f0fdf33pst#endif
37f0fdf33pst
3819bb0b8hselasky#include <pcap-types.h>
3919bb0b8hselasky#ifndef _WIN32
4019bb0b8hselasky#include <sys/param.h>
4119bb0b8hselasky#ifndef MSDOS
4219bb0b8hselasky#include <sys/file.h>
43724e1a0rpaulo#endif
4419bb0b8hselasky#include <sys/ioctl.h>
4519bb0b8hselasky#include <sys/socket.h>
4619bb0b8hselasky#ifdef HAVE_SYS_SOCKIO_H
4719bb0b8hselasky#include <sys/sockio.h>
48724e1a0rpaulo#endif
4919bb0b8hselasky
5019bb0b8hselaskystruct mbuf;		/* Squelch compiler warnings on some platforms for */
5119bb0b8hselaskystruct rtentry;		/* declarations in <net/if.h> */
5219bb0b8hselasky#include <net/if.h>
5319bb0b8hselasky#include <netinet/in.h>
5494960e5delphij#endif /* _WIN32 */
55f0fdf33pst
5619bb0b8hselasky#include <ctype.h>
57f0fdf33pst#include <stdio.h>
58f0fdf33pst#include <stdlib.h>
59f0fdf33pst#include <string.h>
60c5b3ac4gnn#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__)
61f0fdf33pst#include <unistd.h>
62da13a5abms#endif
631e8ea46fenner#include <fcntl.h>
641e8ea46fenner#include <errno.h>
6519bb0b8hselasky#ifdef HAVE_LIMITS_H
6619bb0b8hselasky#include <limits.h>
6719bb0b8hselasky#else
6819bb0b8hselasky#define INT_MAX		2147483647
6919bb0b8hselasky#endif
70f0fdf33pst
71f0fdf33pst#ifdef HAVE_OS_PROTO_H
72f0fdf33pst#include "os-proto.h"
73f0fdf33pst#endif
74f0fdf33pst
7570f7ae4sam#ifdef MSDOS
7670f7ae4sam#include "pcap-dos.h"
7770f7ae4sam#endif
7870f7ae4sam
79f0fdf33pst#include "pcap-int.h"
80f0fdf33pst
8119bb0b8hselasky#include "optimize.h"
8219bb0b8hselasky
83da13a5abms#ifdef HAVE_DAG_API
846181b42delphij#include "pcap-dag.h"
856181b42delphij#endif /* HAVE_DAG_API */
866181b42delphij
876181b42delphij#ifdef HAVE_SEPTEL_API
886181b42delphij#include "pcap-septel.h"
896181b42delphij#endif /* HAVE_SEPTEL_API */
906181b42delphij
916181b42delphij#ifdef HAVE_SNF_API
926181b42delphij#include "pcap-snf.h"
936181b42delphij#endif /* HAVE_SNF_API */
946181b42delphij
9594960e5delphij#ifdef HAVE_TC_API
9694960e5delphij#include "pcap-tc.h"
9794960e5delphij#endif /* HAVE_TC_API */
9894960e5delphij
996181b42delphij#ifdef PCAP_SUPPORT_USB
1006181b42delphij#include "pcap-usb-linux.h"
1016181b42delphij#endif
1026181b42delphij
1036181b42delphij#ifdef PCAP_SUPPORT_BT
1046181b42delphij#include "pcap-bt-linux.h"
1056181b42delphij#endif
1066181b42delphij
107489abeddelphij#ifdef PCAP_SUPPORT_BT_MONITOR
108489abeddelphij#include "pcap-bt-monitor-linux.h"
109489abeddelphij#endif
110489abeddelphij
1116181b42delphij#ifdef PCAP_SUPPORT_NETFILTER
1126181b42delphij#include "pcap-netfilter-linux.h"
113da13a5abms#endif
114da13a5abms
11519bb0b8hselasky#ifdef PCAP_SUPPORT_NETMAP
11619bb0b8hselasky#include "pcap-netmap.h"
11719bb0b8hselasky#endif
11819bb0b8hselasky
119489abeddelphij#ifdef PCAP_SUPPORT_DBUS
120489abeddelphij#include "pcap-dbus.h"
121489abeddelphij#endif
122489abeddelphij
12319bb0b8hselasky#ifdef PCAP_SUPPORT_RDMASNIFF
12419bb0b8hselasky#include "pcap-rdmasniff.h"
12519bb0b8hselasky#endif
12619bb0b8hselasky
12719bb0b8hselasky#ifdef _WIN32
12819bb0b8hselasky/*
12919bb0b8hselasky * DllMain(), required when built as a Windows DLL.
13019bb0b8hselasky */
13119bb0b8hselaskyBOOL WINAPI DllMain(
13219bb0b8hselasky  HANDLE hinstDLL,
13319bb0b8hselasky  DWORD dwReason,
13419bb0b8hselasky  LPVOID lpvReserved
13519bb0b8hselasky)
13619bb0b8hselasky{
13719bb0b8hselasky	return (TRUE);
13819bb0b8hselasky}
13919bb0b8hselasky
14019bb0b8hselasky/*
14119bb0b8hselasky * Start WinSock.
14219bb0b8hselasky * Exported in case some applications using WinPcap called it,
14319bb0b8hselasky * even though it wasn't exported.
14419bb0b8hselasky */
14519bb0b8hselaskyint
14619bb0b8hselaskywsockinit(void)
14719bb0b8hselasky{
14819bb0b8hselasky	WORD wVersionRequested;
14919bb0b8hselasky	WSADATA wsaData;
15019bb0b8hselasky	static int err = -1;
15119bb0b8hselasky	static int done = 0;
15219bb0b8hselasky
15319bb0b8hselasky	if (done)
15419bb0b8hselasky		return (err);
15519bb0b8hselasky
15619bb0b8hselasky	wVersionRequested = MAKEWORD( 1, 1);
15719bb0b8hselasky	err = WSAStartup( wVersionRequested, &wsaData );
15819bb0b8hselasky	atexit ((void(*)(void))WSACleanup);
15919bb0b8hselasky	done = 1;
16019bb0b8hselasky
16119bb0b8hselasky	if ( err != 0 )
16219bb0b8hselasky		err = -1;
16319bb0b8hselasky	return (err);
16419bb0b8hselasky}
16519bb0b8hselasky
16619bb0b8hselasky/*
16719bb0b8hselasky * This is the exported function; new programs should call this.
16819bb0b8hselasky */
16919bb0b8hselaskyint
17019bb0b8hselaskypcap_wsockinit(void)
17119bb0b8hselasky{
17219bb0b8hselasky       return (wsockinit());
17319bb0b8hselasky}
17419bb0b8hselasky#endif /* _WIN32 */
17519bb0b8hselasky
17619bb0b8hselasky/*
17719bb0b8hselasky * String containing the library version.
17819bb0b8hselasky * Not explicitly exported via a header file - the right API to use
17919bb0b8hselasky * is pcap_lib_version() - but some programs included it, so we
18019bb0b8hselasky * provide it.
18119bb0b8hselasky *
18219bb0b8hselasky * We declare it here, right before defining it, to squelch any
18319bb0b8hselasky * warnings we might get from compilers about the lack of a
18419bb0b8hselasky * declaration.
18519bb0b8hselasky */
18619bb0b8hselaskyPCAP_API char pcap_version[];
18719bb0b8hselaskyPCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
18819bb0b8hselasky
18994960e5delphijstatic int
19094960e5delphijpcap_not_initialized(pcap_t *pcap)
191d8d18f6rpaulo{
19219bb0b8hselasky	if (pcap->activated) {
19319bb0b8hselasky		/* A module probably forgot to set the function pointer */
19419bb0b8hselasky		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
19519bb0b8hselasky		    "This operation isn't properly handled by that device");
19619bb0b8hselasky		return (PCAP_ERROR);
19719bb0b8hselasky	}
19894960e5delphij	/* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
19994960e5delphij	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
20094960e5delphij	    "This handle hasn't been activated yet");
201d8d18f6rpaulo	/* this means 'not initialized' */
202c5b3ac4gnn	return (PCAP_ERROR_NOT_ACTIVATED);
203d8d18f6rpaulo}
204d8d18f6rpaulo
20594960e5delphij#ifdef _WIN32
20694960e5delphijstatic void *
20794960e5delphijpcap_not_initialized_ptr(pcap_t *pcap)
20894960e5delphij{
20919bb0b8hselasky	if (pcap->activated) {
21019bb0b8hselasky		/* A module probably forgot to set the function pointer */
21119bb0b8hselasky		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
21219bb0b8hselasky		    "This operation isn't properly handled by that device");
21319bb0b8hselasky		return (NULL);
21419bb0b8hselasky	}
21594960e5delphij	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
21694960e5delphij	    "This handle hasn't been activated yet");
21794960e5delphij	return (NULL);
21894960e5delphij}
21994960e5delphij
22094960e5delphijstatic HANDLE
22194960e5delphijpcap_getevent_not_initialized(pcap_t *pcap)
22294960e5delphij{
22319bb0b8hselasky	if (pcap->activated) {
22419bb0b8hselasky		/* A module probably forgot to set the function pointer */
22519bb0b8hselasky		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
22619bb0b8hselasky		    "This operation isn't properly handled by that device");
22719bb0b8hselasky		return (INVALID_HANDLE_VALUE);
22819bb0b8hselasky	}
22994960e5delphij	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
23094960e5delphij	    "This handle hasn't been activated yet");
23194960e5delphij	return (INVALID_HANDLE_VALUE);
23294960e5delphij}
23394960e5delphij
23494960e5delphijstatic u_int
23594960e5delphijpcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
23694960e5delphij{
23719bb0b8hselasky	if (pcap->activated) {
23819bb0b8hselasky		/* A module probably forgot to set the function pointer */
23919bb0b8hselasky		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
24019bb0b8hselasky		    "This operation isn't properly handled by that device");
24119bb0b8hselasky		return (0);
24219bb0b8hselasky	}
24394960e5delphij	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
24494960e5delphij	    "This handle hasn't been activated yet");
24594960e5delphij	return (0);
24694960e5delphij}
24794960e5delphij
24894960e5delphijstatic PAirpcapHandle
24994960e5delphijpcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
250489abeddelphij{
25119bb0b8hselasky	if (pcap->activated) {
25219bb0b8hselasky		/* A module probably forgot to set the function pointer */
25319bb0b8hselasky		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
25419bb0b8hselasky		    "This operation isn't properly handled by that device");
25519bb0b8hselasky		return (NULL);
25619bb0b8hselasky	}
25794960e5delphij	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
25894960e5delphij	    "This handle hasn't been activated yet");
259489abeddelphij	return (NULL);
260489abeddelphij}
261489abeddelphij#endif
262489abeddelphij
263d8d18f6rpaulo/*
264d8d18f6rpaulo * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't,
265d8d18f6rpaulo * a PCAP_ERROR value on an error.
266d8d18f6rpaulo */
267f0fdf33pstint
268d8d18f6rpaulopcap_can_set_rfmon(pcap_t *p)
269d8d18f6rpaulo{
270d8d18f6rpaulo	return (p->can_set_rfmon_op(p));
271d8d18f6rpaulo}
272d8d18f6rpaulo
273d8d18f6rpaulo/*
274d8d18f6rpaulo * For systems where rfmon mode is never supported.
275d8d18f6rpaulo */
276d8d18f6rpaulostatic int
277d8d18f6rpaulopcap_cant_set_rfmon(pcap_t *p _U_)
278d8d18f6rpaulo{
279d8d18f6rpaulo	return (0);
280d8d18f6rpaulo}
281d8d18f6rpaulo
282724e1a0rpaulo/*
283c5b3ac4gnn * Sets *tstamp_typesp to point to an array 1 or more supported time stamp
284c5b3ac4gnn * types; the return value is the number of supported time stamp types.
285c5b3ac4gnn * The list should be freed by a call to pcap_free_tstamp_types() when
286c5b3ac4gnn * you're done with it.
287c5b3ac4gnn *
288c5b3ac4gnn * A return value of 0 means "you don't get a choice of time stamp type",
289c5b3ac4gnn * in which case *tstamp_typesp is set to null.
290c5b3ac4gnn *
291c5b3ac4gnn * PCAP_ERROR is returned on error.
292c5b3ac4gnn */
293c5b3ac4gnnint
294c5b3ac4gnnpcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
295c5b3ac4gnn{
296c5b3ac4gnn	if (p->tstamp_type_count == 0) {
297c5b3ac4gnn		/*
298c5b3ac4gnn		 * We don't support multiple time stamp types.
299c5b3ac4gnn		 */
300c5b3ac4gnn		*tstamp_typesp = NULL;
301c5b3ac4gnn	} else {
302c5b3ac4gnn		*tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
303c5b3ac4gnn		    p->tstamp_type_count);
304c5b3ac4gnn		if (*tstamp_typesp == NULL) {
30519bb0b8hselasky			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
30619bb0b8hselasky			    errno, "malloc");
307c5b3ac4gnn			return (PCAP_ERROR);
308c5b3ac4gnn		}
309c5b3ac4gnn		(void)memcpy(*tstamp_typesp, p->tstamp_type_list,
310c5b3ac4gnn		    sizeof(**tstamp_typesp) * p->tstamp_type_count);
311c5b3ac4gnn	}
312c5b3ac4gnn	return (p->tstamp_type_count);
313c5b3ac4gnn}
314c5b3ac4gnn
315c5b3ac4gnn/*
316c5b3ac4gnn * In Windows, you might have a library built with one version of the
317c5b3ac4gnn * C runtime library and an application built with another version of
318c5b3ac4gnn * the C runtime library, which means that the library might use one
319c5b3ac4gnn * version of malloc() and free() and the application might use another
320c5b3ac4gnn * version of malloc() and free().  If so, that means something
321c5b3ac4gnn * allocated by the library cannot be freed by the application, so we
322c5b3ac4gnn * need to have a pcap_free_tstamp_types() routine to free up the list
323c5b3ac4gnn * allocated by pcap_list_tstamp_types(), even though it's just a wrapper
324c5b3ac4gnn * around free().
325c5b3ac4gnn */
326c5b3ac4gnnvoid
327c5b3ac4gnnpcap_free_tstamp_types(int *tstamp_type_list)
328c5b3ac4gnn{
329c5b3ac4gnn	free(tstamp_type_list);
330c5b3ac4gnn}
331c5b3ac4gnn
332c5b3ac4gnn/*
333724e1a0rpaulo * Default one-shot callback; overridden for capture types where the
334724e1a0rpaulo * packet data cannot be guaranteed to be available after the callback
335724e1a0rpaulo * returns, so that a copy must be made.
336724e1a0rpaulo */
337489abeddelphijvoid
338724e1a0rpaulopcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt)
339724e1a0rpaulo{
340724e1a0rpaulo	struct oneshot_userdata *sp = (struct oneshot_userdata *)user;
341724e1a0rpaulo
342724e1a0rpaulo	*sp->hdr = *h;
343724e1a0rpaulo	*sp->pkt = pkt;
344724e1a0rpaulo}
345724e1a0rpaulo
346724e1a0rpauloconst u_char *
347724e1a0rpaulopcap_next(pcap_t *p, struct pcap_pkthdr *h)
348724e1a0rpaulo{
349724e1a0rpaulo	struct oneshot_userdata s;
350724e1a0rpaulo	const u_char *pkt;
351724e1a0rpaulo
352724e1a0rpaulo	s.hdr = h;
353724e1a0rpaulo	s.pkt = &pkt;
354724e1a0rpaulo	s.pd = p;
355724e1a0rpaulo	if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0)
356724e1a0rpaulo		return (0);
357724e1a0rpaulo	return (pkt);
358724e1a0rpaulo}
359724e1a0rpaulo
360489abeddelphijint
361724e1a0rpaulopcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
362724e1a0rpaulo    const u_char **pkt_data)
363724e1a0rpaulo{
364724e1a0rpaulo	struct oneshot_userdata s;
365724e1a0rpaulo
366724e1a0rpaulo	s.hdr = &p->pcap_header;
367724e1a0rpaulo	s.pkt = pkt_data;
368724e1a0rpaulo	s.pd = p;
369724e1a0rpaulo
370724e1a0rpaulo	/* Saves a pointer to the packet headers */
371724e1a0rpaulo	*pkt_header= &p->pcap_header;
372724e1a0rpaulo
373489abeddelphij	if (p->rfile != NULL) {
374724e1a0rpaulo		int status;
375724e1a0rpaulo
376724e1a0rpaulo		/* We are on an offline capture */
377c5b3ac4gnn		status = pcap_offline_read(p, 1, p->oneshot_callback,
378c5b3ac4gnn		    (u_char *)&s);
379724e1a0rpaulo
380724e1a0rpaulo		/*
381724e1a0rpaulo		 * Return codes for pcap_offline_read() are:
382724e1a0rpaulo		 *   -  0: EOF
383724e1a0rpaulo		 *   - -1: error
384724e1a0rpaulo		 *   - >1: OK
385724e1a0rpaulo		 * The first one ('0') conflicts with the return code of
386724e1a0rpaulo		 * 0 from pcap_read() meaning "no packets arrived before
387724e1a0rpaulo		 * the timeout expired", so we map it to -2 so you can
388724e1a0rpaulo		 * distinguish between an EOF from a savefile and a
389724e1a0rpaulo		 * "no packets arrived before the timeout expired, try
390724e1a0rpaulo		 * again" from a live capture.
391724e1a0rpaulo		 */
392724e1a0rpaulo		if (status == 0)
393724e1a0rpaulo			return (-2);
394724e1a0rpaulo		else
395724e1a0rpaulo			return (status);
396724e1a0rpaulo	}
397724e1a0rpaulo
398724e1a0rpaulo	/*
399724e1a0rpaulo	 * Return codes for pcap_read() are:
400724e1a0rpaulo	 *   -  0: timeout
401724e1a0rpaulo	 *   - -1: error
402724e1a0rpaulo	 *   - -2: loop was broken out of with pcap_breakloop()
403724e1a0rpaulo	 *   - >1: OK
404724e1a0rpaulo	 * The first one ('0') conflicts with the return code of 0 from
405724e1a0rpaulo	 * pcap_offline_read() meaning "end of file".
406724e1a0rpaulo	*/
407c5b3ac4gnn	return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s));
408724e1a0rpaulo}
409724e1a0rpaulo
41019bb0b8hselasky/*
41119bb0b8hselasky * Implementation of a pcap_if_list_t.
41219bb0b8hselasky */
41319bb0b8hselaskystruct pcap_if_list {
41419bb0b8hselasky	pcap_if_t *beginning;
41519bb0b8hselasky};
41619bb0b8hselasky
41794960e5delphijstatic struct capture_source_type {
41819bb0b8hselasky	int (*findalldevs_op)(pcap_if_list_t *, char *);
4196181b42delphij	pcap_t *(*create_op)(const char *, char *, int *);
4206181b42delphij} capture_source_types[] = {
4216181b42delphij#ifdef HAVE_DAG_API
4226181b42delphij	{ dag_findalldevs, dag_create },
4236181b42delphij#endif
4246181b42delphij#ifdef HAVE_SEPTEL_API
4256181b42delphij	{ septel_findalldevs, septel_create },
4266181b42delphij#endif
4276181b42delphij#ifdef HAVE_SNF_API
4286181b42delphij	{ snf_findalldevs, snf_create },
4296181b42delphij#endif
43094960e5delphij#ifdef HAVE_TC_API
43194960e5delphij	{ TcFindAllDevs, TcCreate },
43294960e5delphij#endif
4336181b42delphij#ifdef PCAP_SUPPORT_BT
4346181b42delphij	{ bt_findalldevs, bt_create },
4356181b42delphij#endif
436489abeddelphij#ifdef PCAP_SUPPORT_BT_MONITOR
437489abeddelphij	{ bt_monitor_findalldevs, bt_monitor_create },
438489abeddelphij#endif
4396181b42delphij#ifdef PCAP_SUPPORT_USB
4406181b42delphij	{ usb_findalldevs, usb_create },
4416181b42delphij#endif
4426181b42delphij#ifdef PCAP_SUPPORT_NETFILTER
4436181b42delphij	{ netfilter_findalldevs, netfilter_create },
4446181b42delphij#endif
44519bb0b8hselasky#ifdef PCAP_SUPPORT_NETMAP
44619bb0b8hselasky	{ pcap_netmap_findalldevs, pcap_netmap_create },
44719bb0b8hselasky#endif
448489abeddelphij#ifdef PCAP_SUPPORT_DBUS
449489abeddelphij	{ dbus_findalldevs, dbus_create },
450489abeddelphij#endif
45119bb0b8hselasky#ifdef PCAP_SUPPORT_RDMASNIFF
45219bb0b8hselasky	{ rdmasniff_findalldevs, rdmasniff_create },
45319bb0b8hselasky#endif
4546181b42delphij	{ NULL, NULL }
4556181b42delphij};
4566181b42delphij
4576181b42delphij/*
4586181b42delphij * Get a list of all capture sources that are up and that we can open.
4596181b42delphij * Returns -1 on error, 0 otherwise.
4606181b42delphij * The list, as returned through "alldevsp", may be null if no interfaces
4616181b42delphij * were up and could be opened.
4626181b42delphij */
4636181b42delphijint
4646181b42delphijpcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
4656181b42delphij{
4666181b42delphij	size_t i;
46719bb0b8hselasky	pcap_if_list_t devlist;
4686181b42delphij
4696181b42delphij	/*
47094960e5delphij	 * Find all the local network interfaces on which we
47194960e5delphij	 * can capture.
4726181b42delphij	 */
47319bb0b8hselasky	devlist.beginning = NULL;
47419bb0b8hselasky	if (pcap_platform_finddevs(&devlist, errbuf) == -1) {
47519bb0b8hselasky		/*
47619bb0b8hselasky		 * Failed - free all of the entries we were given
47719bb0b8hselasky		 * before we failed.
47819bb0b8hselasky		 */
47919bb0b8hselasky		if (devlist.beginning != NULL)
48019bb0b8hselasky			pcap_freealldevs(devlist.beginning);
48119bb0b8hselasky		*alldevsp = NULL;
4826181b42delphij		return (-1);
48319bb0b8hselasky	}
4846181b42delphij
4856181b42delphij	/*
4866181b42delphij	 * Ask each of the non-local-network-interface capture
4876181b42delphij	 * source types what interfaces they have.
4886181b42delphij	 */
4896181b42delphij	for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) {
49019bb0b8hselasky		if (capture_source_types[i].findalldevs_op(&devlist, errbuf) == -1) {
4916181b42delphij			/*
4926181b42delphij			 * We had an error; free the list we've been
4936181b42delphij			 * constructing.
4946181b42delphij			 */
49519bb0b8hselasky			if (devlist.beginning != NULL)
49619bb0b8hselasky				pcap_freealldevs(devlist.beginning);
49719bb0b8hselasky			*alldevsp = NULL;
4986181b42delphij			return (-1);
4996181b42delphij		}
5006181b42delphij	}
501489abeddelphij
50219bb0b8hselasky	/*
50319bb0b8hselasky	 * Return the first entry of the list of all devices.
50419bb0b8hselasky	 */
50519bb0b8hselasky	*alldevsp = devlist.beginning;
5066181b42delphij	return (0);
5076181b42delphij}
5086181b42delphij
50919bb0b8hselaskystatic struct sockaddr *
51019bb0b8hselaskydup_sockaddr(struct sockaddr *sa, size_t sa_length)
5116181b42delphij{
51219bb0b8hselasky	struct sockaddr *newsa;
5136181b42delphij
51419bb0b8hselasky	if ((newsa = malloc(sa_length)) == NULL)
51519bb0b8hselasky		return (NULL);
51619bb0b8hselasky	return (memcpy(newsa, sa, sa_length));
51719bb0b8hselasky}
51819bb0b8hselasky
51919bb0b8hselasky/*
52019bb0b8hselasky * Construct a "figure of merit" for an interface, for use when sorting
52119bb0b8hselasky * the list of interfaces, in which interfaces that are up are superior
52219bb0b8hselasky * to interfaces that aren't up, interfaces that are up and running are
52319bb0b8hselasky * superior to interfaces that are up but not running, and non-loopback
52419bb0b8hselasky * interfaces that are up and running are superior to loopback interfaces,
52519bb0b8hselasky * and interfaces with the same flags have a figure of merit that's higher
52619bb0b8hselasky * the lower the instance number.
52719bb0b8hselasky *
52819bb0b8hselasky * The goal is to try to put the interfaces most likely to be useful for
52919bb0b8hselasky * capture at the beginning of the list.
53019bb0b8hselasky *
53119bb0b8hselasky * The figure of merit, which is lower the "better" the interface is,
53219bb0b8hselasky * has the uppermost bit set if the interface isn't running, the bit
53319bb0b8hselasky * below that set if the interface isn't up, the bit below that set
53419bb0b8hselasky * if the interface is a loopback interface, and the interface index
53519bb0b8hselasky * in the 29 bits below that.  (Yes, we assume u_int is 32 bits.)
53619bb0b8hselasky */
53719bb0b8hselaskystatic u_int
53819bb0b8hselaskyget_figure_of_merit(pcap_if_t *dev)
53919bb0b8hselasky{
54019bb0b8hselasky	const char *cp;
54119bb0b8hselasky	u_int n;
54219bb0b8hselasky
54319bb0b8hselasky	if (strcmp(dev->name, "any") == 0) {
54494960e5delphij		/*
54519bb0b8hselasky		 * Give the "any" device an artificially high instance
54619bb0b8hselasky		 * number, so it shows up after all other non-loopback
54719bb0b8hselasky		 * interfaces.
54894960e5delphij		 */
54919bb0b8hselasky		n = 0x1FFFFFFF;	/* 29 all-1 bits */
55019bb0b8hselasky	} else {
55119bb0b8hselasky		/*
55219bb0b8hselasky		 * A number at the end of the device name string is
55319bb0b8hselasky		 * assumed to be an instance number.  Add 1 to the
55419bb0b8hselasky		 * instance number, and use 0 for "no instance
55519bb0b8hselasky		 * number", so we don't put "no instance number"
55619bb0b8hselasky		 * devices and "instance 0" devices together.
55719bb0b8hselasky		 */
55819bb0b8hselasky		cp = dev->name + strlen(dev->name) - 1;
55919bb0b8hselasky		while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
56019bb0b8hselasky			cp--;
56119bb0b8hselasky		if (*cp >= '0' && *cp <= '9')
56219bb0b8hselasky			n = atoi(cp) + 1;
56319bb0b8hselasky		else
56419bb0b8hselasky			n = 0;
56519bb0b8hselasky	}
56619bb0b8hselasky	if (!(dev->flags & PCAP_IF_RUNNING))
56719bb0b8hselasky		n |= 0x80000000;
56819bb0b8hselasky	if (!(dev->flags & PCAP_IF_UP))
56919bb0b8hselasky		n |= 0x40000000;
57094960e5delphij
57119bb0b8hselasky	/*
57219bb0b8hselasky	 * Give non-wireless interfaces that aren't disconnected a better
57319bb0b8hselasky	 * figure of merit than interfaces that are disconnected, as
57419bb0b8hselasky	 * "disconnected" should indicate that the interface isn't
57519bb0b8hselasky	 * plugged into a network and thus won't give you any traffic.
57619bb0b8hselasky	 *
57719bb0b8hselasky	 * For wireless interfaces, it means "associated with a network",
57819bb0b8hselasky	 * which we presume not to necessarily prevent capture, as you
57919bb0b8hselasky	 * might run the adapter in some flavor of monitor mode.
58019bb0b8hselasky	 */
58119bb0b8hselasky	if (!(dev->flags & PCAP_IF_WIRELESS) &&
58219bb0b8hselasky	    (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
58319bb0b8hselasky		n |= 0x20000000;
58494960e5delphij
58519bb0b8hselasky	/*
58619bb0b8hselasky	 * Sort loopback devices after non-loopback devices, *except* for
58719bb0b8hselasky	 * disconnected devices.
58819bb0b8hselasky	 */
58919bb0b8hselasky	if (dev->flags & PCAP_IF_LOOPBACK)
59019bb0b8hselasky		n |= 0x10000000;
59119bb0b8hselasky
59219bb0b8hselasky	return (n);
59319bb0b8hselasky}
59419bb0b8hselasky
59519bb0b8hselasky#ifndef _WIN32
59619bb0b8hselasky/*
59719bb0b8hselasky * Try to get a description for a given device.
59819bb0b8hselasky * Returns a mallocated description if it could and NULL if it couldn't.
59919bb0b8hselasky *
60019bb0b8hselasky * XXX - on FreeBSDs that support it, should it get the sysctl named
60119bb0b8hselasky * "dev.{adapter family name}.{adapter unit}.%desc" to get a description
60219bb0b8hselasky * of the adapter?  Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800"
60319bb0b8hselasky * with my Cisco 350 card, so the name isn't entirely descriptive.  The
60419bb0b8hselasky * "dev.an.0.%pnpinfo" has a better description, although one might argue
60519bb0b8hselasky * that the problem is really a driver bug - if it can find out that it's
60619bb0b8hselasky * a Cisco 340 or 350, rather than an old Aironet card, it should use
60719bb0b8hselasky * that in the description.
60819bb0b8hselasky *
60919bb0b8hselasky * Do NetBSD, DragonflyBSD, or OpenBSD support this as well?  FreeBSD
61019bb0b8hselasky * and OpenBSD let you get a description, but it's not generated by the OS,
61119bb0b8hselasky * it's set with another ioctl that ifconfig supports; we use that to get
61219bb0b8hselasky * a description in FreeBSD and OpenBSD, but if there is no such
61319bb0b8hselasky * description available, it still might be nice to get some description
61419bb0b8hselasky * string based on the device type or something such as that.
61519bb0b8hselasky *
61619bb0b8hselasky * In macOS, the System Configuration framework can apparently return
61719bb0b8hselasky * names in 10.4 and later.
61819bb0b8hselasky *
61919bb0b8hselasky * It also appears that freedesktop.org's HAL offers an "info.product"
62019bb0b8hselasky * string, but the HAL specification says it "should not be used in any
62119bb0b8hselasky * UI" and "subsystem/capability specific properties" should be used
62219bb0b8hselasky * instead and, in any case, I think HAL is being deprecated in
62319bb0b8hselasky * favor of other stuff such as DeviceKit.  DeviceKit doesn't appear
62419bb0b8hselasky * to have any obvious product information for devices, but maybe
62519bb0b8hselasky * I haven't looked hard enough.
62619bb0b8hselasky *
62719bb0b8hselasky * Using the System Configuration framework, or HAL, or DeviceKit, or
62819bb0b8hselasky * whatever, would require that libpcap applications be linked with
62919bb0b8hselasky * the frameworks/libraries in question.  That shouldn't be a problem
63019bb0b8hselasky * for programs linking with the shared version of libpcap (unless
63119bb0b8hselasky * you're running on AIX - which I think is the only UN*X that doesn't
63219bb0b8hselasky * support linking a shared library with other libraries on which it
63319bb0b8hselasky * depends, and having an executable linked only with the first shared
63419bb0b8hselasky * library automatically pick up the other libraries when started -
63519bb0b8hselasky * and using HAL or whatever).  Programs linked with the static
63619bb0b8hselasky * version of libpcap would have to use pcap-config with the --static
63719bb0b8hselasky * flag in order to get the right linker flags in order to pick up
63819bb0b8hselasky * the additional libraries/frameworks; those programs need that anyway
63919bb0b8hselasky * for libpcap 1.1 and beyond on Linux, as, by default, it requires
64019bb0b8hselasky * -lnl.
64119bb0b8hselasky *
64219bb0b8hselasky * Do any other UN*Xes, or desktop environments support getting a
64319bb0b8hselasky * description?
64419bb0b8hselasky */
64519bb0b8hselaskystatic char *
64619bb0b8hselasky#ifdef SIOCGIFDESCR
64719bb0b8hselaskyget_if_description(const char *name)
64819bb0b8hselasky{
64919bb0b8hselasky	char *description = NULL;
65019bb0b8hselasky	int s;
65119bb0b8hselasky	struct ifreq ifrdesc;
65219bb0b8hselasky#ifndef IFDESCRSIZE
65319bb0b8hselasky	size_t descrlen = 64;
65419bb0b8hselasky#else
65519bb0b8hselasky	size_t descrlen = IFDESCRSIZE;
65619bb0b8hselasky#endif /* IFDESCRSIZE */
6576181b42delphij
6586181b42delphij	/*
65919bb0b8hselasky	 * Get the description for the interface.
6606181b42delphij	 */
66119bb0b8hselasky	memset(&ifrdesc, 0, sizeof ifrdesc);
66219bb0b8hselasky	strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
66319bb0b8hselasky	s = socket(AF_INET, SOCK_DGRAM, 0);
66419bb0b8hselasky	if (s >= 0) {
66519bb0b8hselasky#ifdef __FreeBSD__
66619bb0b8hselasky		/*
66719bb0b8hselasky		 * On FreeBSD, if the buffer isn't big enough for the
66819bb0b8hselasky		 * description, the ioctl succeeds, but the description
66919bb0b8hselasky		 * isn't copied, ifr_buffer.length is set to the description
67019bb0b8hselasky		 * length, and ifr_buffer.buffer is set to NULL.
67119bb0b8hselasky		 */
67219bb0b8hselasky		for (;;) {
67319bb0b8hselasky			free(description);
67419bb0b8hselasky			if ((description = malloc(descrlen)) != NULL) {
67519bb0b8hselasky				ifrdesc.ifr_buffer.buffer = description;
67619bb0b8hselasky				ifrdesc.ifr_buffer.length = descrlen;
67719bb0b8hselasky				if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
67819bb0b8hselasky					if (ifrdesc.ifr_buffer.buffer ==
67919bb0b8hselasky					    description)
68019bb0b8hselasky						break;
68119bb0b8hselasky					else
68219bb0b8hselasky						descrlen = ifrdesc.ifr_buffer.length;
68319bb0b8hselasky				} else {
68419bb0b8hselasky					/*
68519bb0b8hselasky					 * Failed to get interface description.
68619bb0b8hselasky					 */
68719bb0b8hselasky					free(description);
68819bb0b8hselasky					description = NULL;
68919bb0b8hselasky					break;
69019bb0b8hselasky				}
69119bb0b8hselasky			} else
69219bb0b8hselasky				break;
69319bb0b8hselasky		}
69419bb0b8hselasky#else /* __FreeBSD__ */
69519bb0b8hselasky		/*
69619bb0b8hselasky		 * The only other OS that currently supports
69719bb0b8hselasky		 * SIOCGIFDESCR is OpenBSD, and it has no way
69819bb0b8hselasky		 * to get the description length - it's clamped
69919bb0b8hselasky		 * to a maximum of IFDESCRSIZE.
70019bb0b8hselasky		 */
70119bb0b8hselasky		if ((description = malloc(descrlen)) != NULL) {
70219bb0b8hselasky			ifrdesc.ifr_data = (caddr_t)description;
70319bb0b8hselasky			if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
70494960e5delphij				/*
70519bb0b8hselasky				 * Failed to get interface description.
70694960e5delphij				 */
70719bb0b8hselasky				free(description);
70819bb0b8hselasky				description = NULL;
70994960e5delphij			}
71019bb0b8hselasky		}
71119bb0b8hselasky#endif /* __FreeBSD__ */
71219bb0b8hselasky		close(s);
71319bb0b8hselasky		if (description != NULL && strlen(description) == 0) {
71419bb0b8hselasky			/*
71519bb0b8hselasky			 * Description is empty, so discard it.
71619bb0b8hselasky			 */
71719bb0b8hselasky			free(description);
71819bb0b8hselasky			description = NULL;
7196181b42delphij		}
7206181b42delphij	}
7216181b42delphij
72219bb0b8hselasky#ifdef __FreeBSD__
7236181b42delphij	/*
72419bb0b8hselasky	 * For FreeBSD, if we didn't get a description, and this is
72519bb0b8hselasky	 * a device with a name of the form usbusN, label it as a USB
72619bb0b8hselasky	 * bus.
7276181b42delphij	 */
72819bb0b8hselasky	if (description == NULL) {
72919bb0b8hselasky		if (strncmp(name, "usbus", 5) == 0) {
73019bb0b8hselasky			/*
73119bb0b8hselasky			 * OK, it begins with "usbus".
73219bb0b8hselasky			 */
73319bb0b8hselasky			long busnum;
73419bb0b8hselasky			char *p;
73519bb0b8hselasky
73619bb0b8hselasky			errno = 0;
73719bb0b8hselasky			busnum = strtol(name + 5, &p, 10);
73819bb0b8hselasky			if (errno == 0 && p != name + 5 && *p == '\0' &&
73919bb0b8hselasky			    busnum >= 0 && busnum <= INT_MAX) {
74019bb0b8hselasky				/*
74119bb0b8hselasky				 * OK, it's a valid number that's not
74219bb0b8hselasky				 * bigger than INT_MAX.  Construct
74319bb0b8hselasky				 * a description from it.
74419bb0b8hselasky				 */
74519bb0b8hselasky				static const char descr_prefix[] = "USB bus number ";
74619bb0b8hselasky				size_t descr_size;
74719bb0b8hselasky
74819bb0b8hselasky				/*
74919bb0b8hselasky				 * Allow enough room for a 32-bit bus number.
75019bb0b8hselasky				 * sizeof (descr_prefix) includes the
75119bb0b8hselasky				 * terminating NUL.
75219bb0b8hselasky				 */
75319bb0b8hselasky				descr_size = sizeof (descr_prefix) + 10;
75419bb0b8hselasky				description = malloc(descr_size);
75519bb0b8hselasky				if (description != NULL) {
75619bb0b8hselasky					pcap_snprintf(description, descr_size,
75719bb0b8hselasky					    "%s%ld", descr_prefix, busnum);
75819bb0b8hselasky				}
75919bb0b8hselasky			}
76019bb0b8hselasky		}
76194960e5delphij	}
76219bb0b8hselasky#endif
76319bb0b8hselasky	return (description);
76419bb0b8hselasky#else /* SIOCGIFDESCR */
76519bb0b8hselaskyget_if_description(const char *name _U_)
76619bb0b8hselasky{
76719bb0b8hselasky	return (NULL);
76819bb0b8hselasky#endif /* SIOCGIFDESCR */
7696181b42delphij}
7706181b42delphij
77119bb0b8hselasky/*
77219bb0b8hselasky * Look for a given device in the specified list of devices.
77319bb0b8hselasky *
77419bb0b8hselasky * If we find it, return a pointer to its entry.
77519bb0b8hselasky *
77619bb0b8hselasky * If we don't find it, attempt to add an entry for it, with the specified
77719bb0b8hselasky * IFF_ flags and description, and, if that succeeds, return a pointer to
77819bb0b8hselasky * the new entry, otherwise return NULL and set errbuf to an error message.
77919bb0b8hselasky */
78019bb0b8hselaskypcap_if_t *
78119bb0b8hselaskyfind_or_add_if(pcap_if_list_t *devlistp, const char *name,
78219bb0b8hselasky    bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
783724e1a0rpaulo{
78419bb0b8hselasky	bpf_u_int32 pcap_flags;
78519bb0b8hselasky
786724e1a0rpaulo	/*
78719bb0b8hselasky	 * Convert IFF_ flags to pcap flags.
788724e1a0rpaulo	 */
78919bb0b8hselasky	pcap_flags = 0;
79019bb0b8hselasky#ifdef IFF_LOOPBACK
79119bb0b8hselasky	if (if_flags & IFF_LOOPBACK)
79219bb0b8hselasky		pcap_flags |= PCAP_IF_LOOPBACK;
79319bb0b8hselasky#else
794724e1a0rpaulo	/*
79519bb0b8hselasky	 * We don't have IFF_LOOPBACK, so look at the device name to
79619bb0b8hselasky	 * see if it looks like a loopback device.
797724e1a0rpaulo	 */
79819bb0b8hselasky	if (name[0] == 'l' && name[1] == 'o' &&
79919bb0b8hselasky	    (isdigit((unsigned char)(name[2])) || name[2] == '\0')
80019bb0b8hselasky		pcap_flags |= PCAP_IF_LOOPBACK;
80119bb0b8hselasky#endif
80219bb0b8hselasky#ifdef IFF_UP
80319bb0b8hselasky	if (if_flags & IFF_UP)
80419bb0b8hselasky		pcap_flags |= PCAP_IF_UP;
80519bb0b8hselasky#endif
80619bb0b8hselasky#ifdef IFF_RUNNING
80719bb0b8hselasky	if (if_flags & IFF_RUNNING)
80819bb0b8hselasky		pcap_flags |= PCAP_IF_RUNNING;
80919bb0b8hselasky#endif
810724e1a0rpaulo
811724e1a0rpaulo	/*
81219bb0b8hselasky	 * Attempt to find an entry for this device; if we don't find one,
81319bb0b8hselasky	 * attempt to add one.
814724e1a0rpaulo	 */
81519bb0b8hselasky	return (find_or_add_dev(devlistp, name, pcap_flags,
81619bb0b8hselasky	    get_flags_func, get_if_description(name), errbuf));
817724e1a0rpaulo}
818724e1a0rpaulo
81919bb0b8hselasky/*
82019bb0b8hselasky * Look for a given device in the specified list of devices.
82119bb0b8hselasky *
82219bb0b8hselasky * If we find it, then, if the specified address isn't null, add it to
82319bb0b8hselasky * the list of addresses for the device and return 0.
82419bb0b8hselasky *
82519bb0b8hselasky * If we don't find it, attempt to add an entry for it, with the specified
82619bb0b8hselasky * IFF_ flags and description, and, if that succeeds, add the specified
82719bb0b8hselasky * address to its list of addresses if that address is non-null, and
82819bb0b8hselasky * return 0, otherwise return -1 and set errbuf to an error message.
82919bb0b8hselasky *
83019bb0b8hselasky * (We can get called with a null address because we might get a list
83119bb0b8hselasky * of interface name/address combinations from the underlying OS, with
83219bb0b8hselasky * the address being absent in some cases, rather than a list of
83319bb0b8hselasky * interfaces with each interface having a list of addresses, so this
83419bb0b8hselasky * call may be the only call made to add to the list, and we want to
83519bb0b8hselasky * add interfaces even if they have no addresses.)
83619bb0b8hselasky */
83719bb0b8hselaskyint
83819bb0b8hselaskyadd_addr_to_if(pcap_if_list_t *devlistp, const char *name,
83919bb0b8hselasky    bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
84019bb0b8hselasky    struct sockaddr *addr, size_t addr_size,
84119bb0b8hselasky    struct sockaddr *netmask, size_t netmask_size,
84219bb0b8hselasky    struct sockaddr *broadaddr, size_t broadaddr_size,
84319bb0b8hselasky    struct sockaddr *dstaddr, size_t dstaddr_size,
84419bb0b8hselasky    char *errbuf)
845d8d18f6rpaulo{
84619bb0b8hselasky	pcap_if_t *curdev;
847d8d18f6rpaulo
848489abeddelphij	/*
84919bb0b8hselasky	 * Check whether the device exists and, if not, add it.
850489abeddelphij	 */
85119bb0b8hselasky	curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
85219bb0b8hselasky	    errbuf);
85319bb0b8hselasky	if (curdev == NULL) {
85419bb0b8hselasky		/*
85519bb0b8hselasky		 * Error - give up.
85619bb0b8hselasky		 */
85719bb0b8hselasky		return (-1);
85819bb0b8hselasky	}
85919bb0b8hselasky
86019bb0b8hselasky	if (addr == NULL) {
86119bb0b8hselasky		/*
86219bb0b8hselasky		 * There's no address to add; this entry just meant
86319bb0b8hselasky		 * "here's a new interface".
86419bb0b8hselasky		 */
86519bb0b8hselasky		return (0);
866d8d18f6rpaulo	}
867489abeddelphij
868489abeddelphij	/*
86919bb0b8hselasky	 * "curdev" is an entry for this interface, and we have an
87019bb0b8hselasky	 * address for it; add an entry for that address to the
87119bb0b8hselasky	 * interface's list of addresses.
872489abeddelphij	 */
87319bb0b8hselasky	return (add_addr_to_dev(curdev, addr, addr_size, netmask,
87419bb0b8hselasky	    netmask_size, broadaddr, broadaddr_size, dstaddr,
87519bb0b8hselasky	    dstaddr_size, errbuf));
87619bb0b8hselasky}
87719bb0b8hselasky#endif /* _WIN32 */
87819bb0b8hselasky
87919bb0b8hselasky/*
88019bb0b8hselasky * Add an entry to the list of addresses for an interface.
88119bb0b8hselasky * "curdev" is the entry for that interface.
88219bb0b8hselasky */
88319bb0b8hselaskyint
88419bb0b8hselaskyadd_addr_to_dev(pcap_if_t *curdev,
88519bb0b8hselasky    struct sockaddr *addr, size_t addr_size,
88619bb0b8hselasky    struct sockaddr *netmask, size_t netmask_size,
88719bb0b8hselasky    struct sockaddr *broadaddr, size_t broadaddr_size,
88819bb0b8hselasky    struct sockaddr *dstaddr, size_t dstaddr_size,
88919bb0b8hselasky    char *errbuf)
89019bb0b8hselasky{
89119bb0b8hselasky	pcap_addr_t *curaddr, *prevaddr, *nextaddr;
89219bb0b8hselasky
89319bb0b8hselasky	/*
89419bb0b8hselasky	 * Allocate the new entry and fill it in.
89519bb0b8hselasky	 */
89619bb0b8hselasky	curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
89719bb0b8hselasky	if (curaddr == NULL) {
89819bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
89919bb0b8hselasky		    errno, "malloc");
90019bb0b8hselasky		return (-1);
90119bb0b8hselasky	}
90219bb0b8hselasky
90319bb0b8hselasky	curaddr->next = NULL;
90419bb0b8hselasky	if (addr != NULL && addr_size != 0) {
90519bb0b8hselasky		curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
90619bb0b8hselasky		if (curaddr->addr == NULL) {
90719bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
90819bb0b8hselasky			    errno, "malloc");
90919bb0b8hselasky			free(curaddr);
91019bb0b8hselasky			return (-1);
91119bb0b8hselasky		}
91219bb0b8hselasky	} else
91319bb0b8hselasky		curaddr->addr = NULL;
91419bb0b8hselasky
91519bb0b8hselasky	if (netmask != NULL && netmask_size != 0) {
91619bb0b8hselasky		curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
91719bb0b8hselasky		if (curaddr->netmask == NULL) {
91819bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
91919bb0b8hselasky			    errno, "malloc");
92019bb0b8hselasky			if (curaddr->addr != NULL)
92119bb0b8hselasky				free(curaddr->addr);
92219bb0b8hselasky			free(curaddr);
92319bb0b8hselasky			return (-1);
92419bb0b8hselasky		}
92519bb0b8hselasky	} else
92619bb0b8hselasky		curaddr->netmask = NULL;
92719bb0b8hselasky
92819bb0b8hselasky	if (broadaddr != NULL && broadaddr_size != 0) {
92919bb0b8hselasky		curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
93019bb0b8hselasky		if (curaddr->broadaddr == NULL) {
93119bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
93219bb0b8hselasky			    errno, "malloc");
93319bb0b8hselasky			if (curaddr->netmask != NULL)
93419bb0b8hselasky				free(curaddr->netmask);
93519bb0b8hselasky			if (curaddr->addr != NULL)
93619bb0b8hselasky				free(curaddr->addr);
93719bb0b8hselasky			free(curaddr);
93819bb0b8hselasky			return (-1);
93919bb0b8hselasky		}
94019bb0b8hselasky	} else
94119bb0b8hselasky		curaddr->broadaddr = NULL;
94219bb0b8hselasky
94319bb0b8hselasky	if (dstaddr != NULL && dstaddr_size != 0) {
94419bb0b8hselasky		curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
94519bb0b8hselasky		if (curaddr->dstaddr == NULL) {
94619bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
94719bb0b8hselasky			    errno, "malloc");
94819bb0b8hselasky			if (curaddr->broadaddr != NULL)
94919bb0b8hselasky				free(curaddr->broadaddr);
95019bb0b8hselasky			if (curaddr->netmask != NULL)
95119bb0b8hselasky				free(curaddr->netmask);
95219bb0b8hselasky			if (curaddr->addr != NULL)
95319bb0b8hselasky				free(curaddr->addr);
95419bb0b8hselasky			free(curaddr);
95519bb0b8hselasky			return (-1);
95619bb0b8hselasky		}
95719bb0b8hselasky	} else
95819bb0b8hselasky		curaddr->dstaddr = NULL;
95919bb0b8hselasky
96019bb0b8hselasky	/*
96119bb0b8hselasky	 * Find the end of the list of addresses.
96219bb0b8hselasky	 */
96319bb0b8hselasky	for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
96419bb0b8hselasky		nextaddr = prevaddr->next;
96519bb0b8hselasky		if (nextaddr == NULL) {
96619bb0b8hselasky			/*
96719bb0b8hselasky			 * This is the end of the list.
96819bb0b8hselasky			 */
96919bb0b8hselasky			break;
97019bb0b8hselasky		}
97119bb0b8hselasky	}
97219bb0b8hselasky
97319bb0b8hselasky	if (prevaddr == NULL) {
97419bb0b8hselasky		/*
97519bb0b8hselasky		 * The list was empty; this is the first member.
97619bb0b8hselasky		 */
97719bb0b8hselasky		curdev->addresses = curaddr;
97819bb0b8hselasky	} else {
97919bb0b8hselasky		/*
98019bb0b8hselasky		 * "prevaddr" is the last member of the list; append
98119bb0b8hselasky		 * this member to it.
98219bb0b8hselasky		 */
98319bb0b8hselasky		prevaddr->next = curaddr;
98419bb0b8hselasky	}
98519bb0b8hselasky
98619bb0b8hselasky	return (0);
98719bb0b8hselasky}
98819bb0b8hselasky
98919bb0b8hselasky/*
99019bb0b8hselasky * Look for a given device in the specified list of devices.
99119bb0b8hselasky *
99219bb0b8hselasky * If we find it, return 0 and set *curdev_ret to point to it.
99319bb0b8hselasky *
99419bb0b8hselasky * If we don't find it, attempt to add an entry for it, with the specified
99519bb0b8hselasky * flags and description, and, if that succeeds, return 0, otherwise
99619bb0b8hselasky * return -1 and set errbuf to an error message.
99719bb0b8hselasky */
99819bb0b8hselaskypcap_if_t *
99919bb0b8hselaskyfind_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
100019bb0b8hselasky    get_if_flags_func get_flags_func, const char *description, char *errbuf)
100119bb0b8hselasky{
100219bb0b8hselasky	pcap_if_t *curdev;
100319bb0b8hselasky
100419bb0b8hselasky	/*
100519bb0b8hselasky	 * Is there already an entry in the list for this device?
100619bb0b8hselasky	 */
100719bb0b8hselasky	curdev = find_dev(devlistp, name);
100819bb0b8hselasky	if (curdev != NULL) {
100919bb0b8hselasky		/*
101019bb0b8hselasky		 * Yes, return it.
101119bb0b8hselasky		 */
101219bb0b8hselasky		return (curdev);
101319bb0b8hselasky	}
101419bb0b8hselasky
101519bb0b8hselasky	/*
101619bb0b8hselasky	 * No, we didn't find it.
101719bb0b8hselasky	 */
101819bb0b8hselasky
101919bb0b8hselasky	/*
102019bb0b8hselasky	 * Try to get additional flags for the device.
102119bb0b8hselasky	 */
102219bb0b8hselasky	if ((*get_flags_func)(name, &flags, errbuf) == -1) {
102319bb0b8hselasky		/*
102419bb0b8hselasky		 * Failed.
102519bb0b8hselasky		 */
102619bb0b8hselasky		return (NULL);
102719bb0b8hselasky	}
102819bb0b8hselasky
102919bb0b8hselasky	/*
103019bb0b8hselasky	 * Now, try to add it to the list of devices.
103119bb0b8hselasky	 */
103219bb0b8hselasky	return (add_dev(devlistp, name, flags, description, errbuf));
103319bb0b8hselasky}
103419bb0b8hselasky
103519bb0b8hselasky/*
103619bb0b8hselasky * Look for a given device in the specified list of devices, and return
103719bb0b8hselasky * the entry for it if we find it or NULL if we don't.
103819bb0b8hselasky */
103919bb0b8hselaskypcap_if_t *
104019bb0b8hselaskyfind_dev(pcap_if_list_t *devlistp, const char *name)
104119bb0b8hselasky{
104219bb0b8hselasky	pcap_if_t *curdev;
104319bb0b8hselasky
104419bb0b8hselasky	/*
104519bb0b8hselasky	 * Is there an entry in the list for this device?
104619bb0b8hselasky	 */
104719bb0b8hselasky	for (curdev = devlistp->beginning; curdev != NULL;
104819bb0b8hselasky	    curdev = curdev->next) {
104919bb0b8hselasky		if (strcmp(name, curdev->name) == 0) {
105019bb0b8hselasky			/*
105119bb0b8hselasky			 * We found it, so, yes, there is.  No need to
105219bb0b8hselasky			 * add it.  Provide the entry we found to our
105319bb0b8hselasky			 * caller.
105419bb0b8hselasky			 */
105519bb0b8hselasky			return (curdev);
105619bb0b8hselasky		}
105719bb0b8hselasky	}
105819bb0b8hselasky
105919bb0b8hselasky	/*
106019bb0b8hselasky	 * No.
106119bb0b8hselasky	 */
106219bb0b8hselasky	return (NULL);
106319bb0b8hselasky}
106419bb0b8hselasky
106519bb0b8hselasky/*
106619bb0b8hselasky * Attempt to add an entry for a device, with the specified flags
106719bb0b8hselasky * and description, and, if that succeeds, return 0 and return a pointer
106819bb0b8hselasky * to the new entry, otherwise return NULL and set errbuf to an error
106919bb0b8hselasky * message.
107019bb0b8hselasky *
107119bb0b8hselasky * If we weren't given a description, try to get one.
107219bb0b8hselasky */
107319bb0b8hselaskypcap_if_t *
107419bb0b8hselaskyadd_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
107519bb0b8hselasky    const char *description, char *errbuf)
107619bb0b8hselasky{
107719bb0b8hselasky	pcap_if_t *curdev, *prevdev, *nextdev;
107819bb0b8hselasky	u_int this_figure_of_merit, nextdev_figure_of_merit;
107919bb0b8hselasky
108019bb0b8hselasky	curdev = malloc(sizeof(pcap_if_t));
108119bb0b8hselasky	if (curdev == NULL) {
108219bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
108319bb0b8hselasky		    errno, "malloc");
108419bb0b8hselasky		return (NULL);
108519bb0b8hselasky	}
108619bb0b8hselasky
108719bb0b8hselasky	/*
108819bb0b8hselasky	 * Fill in the entry.
108919bb0b8hselasky	 */
109019bb0b8hselasky	curdev->next = NULL;
109119bb0b8hselasky	curdev->name = strdup(name);
109219bb0b8hselasky	if (curdev->name == NULL) {
109319bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
109419bb0b8hselasky		    errno, "malloc");
109519bb0b8hselasky		free(curdev);
109619bb0b8hselasky		return (NULL);
109719bb0b8hselasky	}
109819bb0b8hselasky	if (description == NULL) {
109919bb0b8hselasky		/*
110019bb0b8hselasky		 * We weren't handed a description for the interface.
110119bb0b8hselasky		 */
110219bb0b8hselasky		curdev->description = NULL;
110319bb0b8hselasky	} else {
110419bb0b8hselasky		/*
110519bb0b8hselasky		 * We were handed a description; make a copy.
110619bb0b8hselasky		 */
110719bb0b8hselasky		curdev->description = strdup(description);
110819bb0b8hselasky		if (curdev->description == NULL) {
110919bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
111019bb0b8hselasky			    errno, "malloc");
111119bb0b8hselasky			free(curdev->name);
111219bb0b8hselasky			free(curdev);
111319bb0b8hselasky			return (NULL);
111419bb0b8hselasky		}
111519bb0b8hselasky	}
111619bb0b8hselasky	curdev->addresses = NULL;	/* list starts out as empty */
111719bb0b8hselasky	curdev->flags = flags;
111819bb0b8hselasky
111919bb0b8hselasky	/*
112019bb0b8hselasky	 * Add it to the list, in the appropriate location.
112119bb0b8hselasky	 * First, get the "figure of merit" for this interface.
112219bb0b8hselasky	 */
112319bb0b8hselasky	this_figure_of_merit = get_figure_of_merit(curdev);
112419bb0b8hselasky
112519bb0b8hselasky	/*
112619bb0b8hselasky	 * Now look for the last interface with an figure of merit
112719bb0b8hselasky	 * less than or equal to the new interface's figure of merit.
112819bb0b8hselasky	 *
112919bb0b8hselasky	 * We start with "prevdev" being NULL, meaning we're before
113019bb0b8hselasky	 * the first element in the list.
113119bb0b8hselasky	 */
113219bb0b8hselasky	prevdev = NULL;
113319bb0b8hselasky	for (;;) {
113419bb0b8hselasky		/*
113519bb0b8hselasky		 * Get the interface after this one.
113619bb0b8hselasky		 */
113719bb0b8hselasky		if (prevdev == NULL) {
113819bb0b8hselasky			/*
113919bb0b8hselasky			 * The next element is the first element.
114019bb0b8hselasky			 */
114119bb0b8hselasky			nextdev = devlistp->beginning;
114219bb0b8hselasky		} else
114319bb0b8hselasky			nextdev = prevdev->next;
114419bb0b8hselasky
114519bb0b8hselasky		/*
114619bb0b8hselasky		 * Are we at the end of the list?
114719bb0b8hselasky		 */
114819bb0b8hselasky		if (nextdev == NULL) {
114919bb0b8hselasky			/*
115019bb0b8hselasky			 * Yes - we have to put the new entry after "prevdev".
115119bb0b8hselasky			 */
115219bb0b8hselasky			break;
115319bb0b8hselasky		}
115419bb0b8hselasky
115519bb0b8hselasky		/*
115619bb0b8hselasky		 * Is the new interface's figure of merit less
115719bb0b8hselasky		 * than the next interface's figure of merit,
115819bb0b8hselasky		 * meaning that the new interface is better
115919bb0b8hselasky		 * than the next interface?
116019bb0b8hselasky		 */
116119bb0b8hselasky		nextdev_figure_of_merit = get_figure_of_merit(nextdev);
116219bb0b8hselasky		if (this_figure_of_merit < nextdev_figure_of_merit) {
116319bb0b8hselasky			/*
116419bb0b8hselasky			 * Yes - we should put the new entry
116519bb0b8hselasky			 * before "nextdev", i.e. after "prevdev".
116619bb0b8hselasky			 */
116719bb0b8hselasky			break;
116819bb0b8hselasky		}
116919bb0b8hselasky
117019bb0b8hselasky		prevdev = nextdev;
117119bb0b8hselasky	}
117219bb0b8hselasky
117319bb0b8hselasky	/*
117419bb0b8hselasky	 * Insert before "nextdev".
117519bb0b8hselasky	 */
117619bb0b8hselasky	curdev->next = nextdev;
117719bb0b8hselasky
117819bb0b8hselasky	/*
117919bb0b8hselasky	 * Insert after "prevdev" - unless "prevdev" is null,
118019bb0b8hselasky	 * in which case this is the first interface.
118119bb0b8hselasky	 */
118219bb0b8hselasky	if (prevdev == NULL) {
118319bb0b8hselasky		/*
118419bb0b8hselasky		 * This is the first interface.  Make it
118519bb0b8hselasky		 * the first element in the list of devices.
118619bb0b8hselasky		 */
118719bb0b8hselasky		devlistp->beginning = curdev;
118819bb0b8hselasky	} else
118919bb0b8hselasky		prevdev->next = curdev;
119019bb0b8hselasky	return (curdev);
119119bb0b8hselasky}
119219bb0b8hselasky
119319bb0b8hselasky/*
119419bb0b8hselasky * Free a list of interfaces.
119519bb0b8hselasky */
119619bb0b8hselaskyvoid
119719bb0b8hselaskypcap_freealldevs(pcap_if_t *alldevs)
119819bb0b8hselasky{
119919bb0b8hselasky	pcap_if_t *curdev, *nextdev;
120019bb0b8hselasky	pcap_addr_t *curaddr, *nextaddr;
120119bb0b8hselasky
120219bb0b8hselasky	for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
120319bb0b8hselasky		nextdev = curdev->next;
120419bb0b8hselasky
120519bb0b8hselasky		/*
120619bb0b8hselasky		 * Free all addresses.
120719bb0b8hselasky		 */
120819bb0b8hselasky		for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
120919bb0b8hselasky			nextaddr = curaddr->next;
121019bb0b8hselasky			if (curaddr->addr)
121119bb0b8hselasky				free(curaddr->addr);
121219bb0b8hselasky			if (curaddr->netmask)
121319bb0b8hselasky				free(curaddr->netmask);
121419bb0b8hselasky			if (curaddr->broadaddr)
121519bb0b8hselasky				free(curaddr->broadaddr);
121619bb0b8hselasky			if (curaddr->dstaddr)
121719bb0b8hselasky				free(curaddr->dstaddr);
121819bb0b8hselasky			free(curaddr);
121919bb0b8hselasky		}
122019bb0b8hselasky
122119bb0b8hselasky		/*
122219bb0b8hselasky		 * Free the name string.
122319bb0b8hselasky		 */
122419bb0b8hselasky		free(curdev->name);
122519bb0b8hselasky
122619bb0b8hselasky		/*
122719bb0b8hselasky		 * Free the description string, if any.
122819bb0b8hselasky		 */
122919bb0b8hselasky		if (curdev->description != NULL)
123019bb0b8hselasky			free(curdev->description);
123119bb0b8hselasky
123219bb0b8hselasky		/*
123319bb0b8hselasky		 * Free the interface.
123419bb0b8hselasky		 */
123519bb0b8hselasky		free(curdev);
123619bb0b8hselasky	}
123719bb0b8hselasky}
123819bb0b8hselasky
123919bb0b8hselasky/*
124019bb0b8hselasky * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
124119bb0b8hselasky * it actually returns the names of all interfaces, with a NUL separator
124219bb0b8hselasky * between them; some callers may depend on that.
124319bb0b8hselasky *
124419bb0b8hselasky * MS-DOS has its own pcap_lookupdev(), but that might be useful only
124519bb0b8hselasky * as an optimization.
124619bb0b8hselasky *
124719bb0b8hselasky * In all other cases, we just use pcap_findalldevs() to get a list of
124819bb0b8hselasky * devices, and pick from that list.
124919bb0b8hselasky */
125019bb0b8hselasky#if !defined(HAVE_PACKET32) && !defined(MSDOS)
125119bb0b8hselasky/*
125219bb0b8hselasky * Return the name of a network interface attached to the system, or NULL
125319bb0b8hselasky * if none can be found.  The interface must be configured up; the
125419bb0b8hselasky * lowest unit number is preferred; loopback is ignored.
125519bb0b8hselasky */
125619bb0b8hselaskychar *
125719bb0b8hselaskypcap_lookupdev(char *errbuf)
125819bb0b8hselasky{
125919bb0b8hselasky	pcap_if_t *alldevs;
126019bb0b8hselasky#ifdef _WIN32
126119bb0b8hselasky  /*
126219bb0b8hselasky   * Windows - use the same size as the old WinPcap 3.1 code.
126319bb0b8hselasky   * XXX - this is probably bigger than it needs to be.
126419bb0b8hselasky   */
126519bb0b8hselasky  #define IF_NAMESIZE 8192
126619bb0b8hselasky#else
126719bb0b8hselasky  /*
126819bb0b8hselasky   * UN*X - use the system's interface name size.
126919bb0b8hselasky   * XXX - that might not be large enough for capture devices
127019bb0b8hselasky   * that aren't regular network interfaces.
127119bb0b8hselasky   */
127219bb0b8hselasky  /* for old BSD systems, including bsdi3 */
127319bb0b8hselasky  #ifndef IF_NAMESIZE
127419bb0b8hselasky  #define IF_NAMESIZE IFNAMSIZ
127519bb0b8hselasky  #endif
127619bb0b8hselasky#endif
127719bb0b8hselasky	static char device[IF_NAMESIZE + 1];
127819bb0b8hselasky	char *ret;
127919bb0b8hselasky
128019bb0b8hselasky	if (pcap_findalldevs(&alldevs, errbuf) == -1)
128119bb0b8hselasky		return (NULL);
128219bb0b8hselasky
128319bb0b8hselasky	if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
128419bb0b8hselasky		/*
128519bb0b8hselasky		 * There are no devices on the list, or the first device
128619bb0b8hselasky		 * on the list is a loopback device, which means there
128719bb0b8hselasky		 * are no non-loopback devices on the list.  This means
128819bb0b8hselasky		 * we can't return any device.
128919bb0b8hselasky		 *
129019bb0b8hselasky		 * XXX - why not return a loopback device?  If we can't
129119bb0b8hselasky		 * capture on it, it won't be on the list, and if it's
129219bb0b8hselasky		 * on the list, there aren't any non-loopback devices,
129319bb0b8hselasky		 * so why not just supply it as the default device?
129419bb0b8hselasky		 */
129519bb0b8hselasky		(void)strlcpy(errbuf, "no suitable device found",
129619bb0b8hselasky		    PCAP_ERRBUF_SIZE);
129719bb0b8hselasky		ret = NULL;
129819bb0b8hselasky	} else {
129919bb0b8hselasky		/*
130019bb0b8hselasky		 * Return the name of the first device on the list.
130119bb0b8hselasky		 */
130219bb0b8hselasky		(void)strlcpy(device, alldevs->name, sizeof(device));
130319bb0b8hselasky		ret = device;
130419bb0b8hselasky	}
130519bb0b8hselasky
130619bb0b8hselasky	pcap_freealldevs(alldevs);
130719bb0b8hselasky	return (ret);
130819bb0b8hselasky}
130919bb0b8hselasky#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
131019bb0b8hselasky
131119bb0b8hselasky#if !defined(_WIN32) && !defined(MSDOS)
131219bb0b8hselasky/*
131319bb0b8hselasky * We don't just fetch the entire list of devices, search for the
131419bb0b8hselasky * particular device, and use its first IPv4 address, as that's too
131519bb0b8hselasky * much work to get just one device's netmask.
131619bb0b8hselasky *
131719bb0b8hselasky * If we had an API to get attributes for a given device, we could
131819bb0b8hselasky * use that.
131919bb0b8hselasky */
132019bb0b8hselaskyint
132119bb0b8hselaskypcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
132219bb0b8hselasky    char *errbuf)
132319bb0b8hselasky{
132419bb0b8hselasky	register int fd;
132519bb0b8hselasky	register struct sockaddr_in *sin4;
132619bb0b8hselasky	struct ifreq ifr;
132719bb0b8hselasky
132819bb0b8hselasky	/*
132919bb0b8hselasky	 * The pseudo-device "any" listens on all interfaces and therefore
133019bb0b8hselasky	 * has the network address and -mask "0.0.0.0" therefore catching
133119bb0b8hselasky	 * all traffic. Using NULL for the interface is the same as "any".
133219bb0b8hselasky	 */
133319bb0b8hselasky	if (!device || strcmp(device, "any") == 0
133419bb0b8hselasky#ifdef HAVE_DAG_API
133519bb0b8hselasky	    || strstr(device, "dag") != NULL
133619bb0b8hselasky#endif
133719bb0b8hselasky#ifdef HAVE_SEPTEL_API
133819bb0b8hselasky	    || strstr(device, "septel") != NULL
133919bb0b8hselasky#endif
134019bb0b8hselasky#ifdef PCAP_SUPPORT_BT
134119bb0b8hselasky	    || strstr(device, "bluetooth") != NULL
134219bb0b8hselasky#endif
134319bb0b8hselasky#ifdef PCAP_SUPPORT_USB
134419bb0b8hselasky	    || strstr(device, "usbmon") != NULL
134519bb0b8hselasky#endif
134619bb0b8hselasky#ifdef HAVE_SNF_API
134719bb0b8hselasky	    || strstr(device, "snf") != NULL
134819bb0b8hselasky#endif
134919bb0b8hselasky#ifdef PCAP_SUPPORT_NETMAP
135019bb0b8hselasky	    || strncmp(device, "netmap:", 7) == 0
135119bb0b8hselasky	    || strncmp(device, "vale", 4) == 0
135219bb0b8hselasky#endif
135319bb0b8hselasky	    ) {
135419bb0b8hselasky		*netp = *maskp = 0;
135519bb0b8hselasky		return 0;
135619bb0b8hselasky	}
135719bb0b8hselasky
135819bb0b8hselasky	fd = socket(AF_INET, SOCK_DGRAM, 0);
135919bb0b8hselasky	if (fd < 0) {
136019bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
136119bb0b8hselasky		    errno, "socket");
136219bb0b8hselasky		return (-1);
136319bb0b8hselasky	}
136419bb0b8hselasky	memset(&ifr, 0, sizeof(ifr));
136519bb0b8hselasky#ifdef linux
136619bb0b8hselasky	/* XXX Work around Linux kernel bug */
136719bb0b8hselasky	ifr.ifr_addr.sa_family = AF_INET;
136819bb0b8hselasky#endif
136919bb0b8hselasky	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
137019bb0b8hselasky	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
137119bb0b8hselasky		if (errno == EADDRNOTAVAIL) {
137219bb0b8hselasky			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
137319bb0b8hselasky			    "%s: no IPv4 address assigned", device);
137419bb0b8hselasky		} else {
137519bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
137619bb0b8hselasky			    errno, "SIOCGIFADDR: %s", device);
137719bb0b8hselasky		}
137819bb0b8hselasky		(void)close(fd);
137919bb0b8hselasky		return (-1);
138019bb0b8hselasky	}
138119bb0b8hselasky	sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
138219bb0b8hselasky	*netp = sin4->sin_addr.s_addr;
138319bb0b8hselasky	memset(&ifr, 0, sizeof(ifr));
138419bb0b8hselasky#ifdef linux
138519bb0b8hselasky	/* XXX Work around Linux kernel bug */
138619bb0b8hselasky	ifr.ifr_addr.sa_family = AF_INET;
138719bb0b8hselasky#endif
138819bb0b8hselasky	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
138919bb0b8hselasky	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
139019bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
139119bb0b8hselasky		    errno, "SIOCGIFNETMASK: %s", device);
139219bb0b8hselasky		(void)close(fd);
139319bb0b8hselasky		return (-1);
139419bb0b8hselasky	}
139519bb0b8hselasky	(void)close(fd);
139619bb0b8hselasky	*maskp = sin4->sin_addr.s_addr;
139719bb0b8hselasky	if (*maskp == 0) {
139819bb0b8hselasky		if (IN_CLASSA(*netp))
139919bb0b8hselasky			*maskp = IN_CLASSA_NET;
140019bb0b8hselasky		else if (IN_CLASSB(*netp))
140119bb0b8hselasky			*maskp = IN_CLASSB_NET;
140219bb0b8hselasky		else if (IN_CLASSC(*netp))
140319bb0b8hselasky			*maskp = IN_CLASSC_NET;
140419bb0b8hselasky		else {
140519bb0b8hselasky			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
140619bb0b8hselasky			    "inet class for 0x%x unknown", *netp);
140719bb0b8hselasky			return (-1);
140819bb0b8hselasky		}
140919bb0b8hselasky	}
141019bb0b8hselasky	*netp &= *maskp;
141119bb0b8hselasky	return (0);
141219bb0b8hselasky}
141319bb0b8hselasky#endif /* !defined(_WIN32) && !defined(MSDOS) */
141419bb0b8hselasky
141519bb0b8hselasky#ifdef ENABLE_REMOTE
141619bb0b8hselasky#include "pcap-rpcap.h"
141719bb0b8hselasky
141819bb0b8hselasky/*
141919bb0b8hselasky * Extract a substring from a string.
142019bb0b8hselasky */
142119bb0b8hselaskystatic char *
142219bb0b8hselaskyget_substring(const char *p, size_t len, char *ebuf)
142319bb0b8hselasky{
142419bb0b8hselasky	char *token;
142519bb0b8hselasky
142619bb0b8hselasky	token = malloc(len + 1);
142719bb0b8hselasky	if (token == NULL) {
142819bb0b8hselasky		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
142919bb0b8hselasky		    errno, "malloc");
143019bb0b8hselasky		return (NULL);
143119bb0b8hselasky	}
143219bb0b8hselasky	memcpy(token, p, len);
143319bb0b8hselasky	token[len] = '\0';
143419bb0b8hselasky	return (token);
143519bb0b8hselasky}
143619bb0b8hselasky
143719bb0b8hselasky/*
143819bb0b8hselasky * Parse a capture source that might be a URL.
143919bb0b8hselasky *
144019bb0b8hselasky * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
144119bb0b8hselasky * are set to NULL, *pathp is set to point to the source, and 0 is
144219bb0b8hselasky * returned.
144319bb0b8hselasky *
144419bb0b8hselasky * If source is a URL, and the URL refers to a local device (a special
144519bb0b8hselasky * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
144619bb0b8hselasky * to NULL, *pathp is set to point to the device name, and 0 is returned.
144719bb0b8hselasky *
144819bb0b8hselasky * If source is a URL, and it's not a special case that refers to a local
144919bb0b8hselasky * device, and the parse succeeds:
145019bb0b8hselasky *
145119bb0b8hselasky *    *schemep is set to point to an allocated string containing the scheme;
145219bb0b8hselasky *
145319bb0b8hselasky *    if user information is present in the URL, *userinfop is set to point
145419bb0b8hselasky *    to an allocated string containing the user information, otherwise
145519bb0b8hselasky *    it's set to NULL;
145619bb0b8hselasky *
145719bb0b8hselasky *    if host information is present in the URL, *hostp is set to point
145819bb0b8hselasky *    to an allocated string containing the host information, otherwise
145919bb0b8hselasky *    it's set to NULL;
146019bb0b8hselasky *
146119bb0b8hselasky *    if a port number is present in the URL, *portp is set to point
146219bb0b8hselasky *    to an allocated string containing the port number, otherwise
146319bb0b8hselasky *    it's set to NULL;
146419bb0b8hselasky *
146519bb0b8hselasky *    *pathp is set to point to an allocated string containing the
146619bb0b8hselasky *    path;
146719bb0b8hselasky *
146819bb0b8hselasky * and 0 is returned.
146919bb0b8hselasky *
147019bb0b8hselasky * If the parse fails, ebuf is set to an error string, and -1 is returned.
147119bb0b8hselasky */
147219bb0b8hselaskystatic int
147319bb0b8hselaskypcap_parse_source(const char *source, char **schemep, char **userinfop,
147419bb0b8hselasky    char **hostp, char **portp, char **pathp, char *ebuf)
147519bb0b8hselasky{
147619bb0b8hselasky	char *colonp;
147719bb0b8hselasky	size_t scheme_len;
147819bb0b8hselasky	char *scheme;
147919bb0b8hselasky	const char *endp;
148019bb0b8hselasky	size_t authority_len;
148119bb0b8hselasky	char *authority;
148219bb0b8hselasky	char *parsep, *atsignp, *bracketp;
148319bb0b8hselasky	char *userinfo, *host, *port, *path;
148419bb0b8hselasky
148519bb0b8hselasky	/*
148619bb0b8hselasky	 * Start out returning nothing.
148719bb0b8hselasky	 */
148819bb0b8hselasky	*schemep = NULL;
148919bb0b8hselasky	*userinfop = NULL;
149019bb0b8hselasky	*hostp = NULL;
149119bb0b8hselasky	*portp = NULL;
149219bb0b8hselasky	*pathp = NULL;
149319bb0b8hselasky
149419bb0b8hselasky	/*
149519bb0b8hselasky	 * RFC 3986 says:
149619bb0b8hselasky	 *
149719bb0b8hselasky	 *   URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
149819bb0b8hselasky	 *
149919bb0b8hselasky	 *   hier-part   = "//" authority path-abempty
150019bb0b8hselasky	 *               / path-absolute
150119bb0b8hselasky	 *               / path-rootless
150219bb0b8hselasky	 *               / path-empty
150319bb0b8hselasky	 *
150419bb0b8hselasky	 *   authority   = [ userinfo "@" ] host [ ":" port ]
150519bb0b8hselasky	 *
150619bb0b8hselasky	 *   userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
150719bb0b8hselasky         *
150819bb0b8hselasky         * Step 1: look for the ":" at the end of the scheme.
150919bb0b8hselasky	 * A colon in the source is *NOT* sufficient to indicate that
151019bb0b8hselasky	 * this is a URL, as interface names on some platforms might
151119bb0b8hselasky	 * include colons (e.g., I think some Solaris interfaces
151219bb0b8hselasky	 * might).
151319bb0b8hselasky	 */
151419bb0b8hselasky	colonp = strchr(source, ':');
151519bb0b8hselasky	if (colonp == NULL) {
151619bb0b8hselasky		/*
151719bb0b8hselasky		 * The source is the device to open.
151819bb0b8hselasky		 * Return a NULL pointer for the scheme, user information,
151919bb0b8hselasky		 * host, and port, and return the device as the path.
152019bb0b8hselasky		 */
152119bb0b8hselasky		*pathp = strdup(source);
152219bb0b8hselasky		if (*pathp == NULL) {
152319bb0b8hselasky			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
152419bb0b8hselasky			    errno, "malloc");
152519bb0b8hselasky			return (-1);
152619bb0b8hselasky		}
152719bb0b8hselasky		return (0);
152819bb0b8hselasky	}
152919bb0b8hselasky
153019bb0b8hselasky	/*
153119bb0b8hselasky	 * All schemes must have "//" after them, i.e. we only support
153219bb0b8hselasky	 * hier-part   = "//" authority path-abempty, not
153319bb0b8hselasky	 * hier-part   = path-absolute
153419bb0b8hselasky	 * hier-part   = path-rootless
153519bb0b8hselasky	 * hier-part   = path-empty
153619bb0b8hselasky	 *
153719bb0b8hselasky	 * We need that in order to distinguish between a local device
153819bb0b8hselasky	 * name that happens to contain a colon and a URI.
153919bb0b8hselasky	 */
154019bb0b8hselasky	if (strncmp(colonp + 1, "//", 2) != 0) {
154119bb0b8hselasky		/*
154219bb0b8hselasky		 * The source is the device to open.
154319bb0b8hselasky		 * Return a NULL pointer for the scheme, user information,
154419bb0b8hselasky		 * host, and port, and return the device as the path.
154519bb0b8hselasky		 */
154619bb0b8hselasky		*pathp = strdup(source);
154719bb0b8hselasky		if (*pathp == NULL) {
154819bb0b8hselasky			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
154919bb0b8hselasky			    errno, "malloc");
155019bb0b8hselasky			return (-1);
155119bb0b8hselasky		}
155219bb0b8hselasky		return (0);
155319bb0b8hselasky	}
155419bb0b8hselasky
155519bb0b8hselasky	/*
155619bb0b8hselasky	 * XXX - check whether the purported scheme could be a scheme?
155719bb0b8hselasky	 */
155819bb0b8hselasky
155919bb0b8hselasky	/*
156019bb0b8hselasky	 * OK, this looks like a URL.
156119bb0b8hselasky	 * Get the scheme.
156219bb0b8hselasky	 */
156319bb0b8hselasky	scheme_len = colonp - source;
156419bb0b8hselasky	scheme = malloc(scheme_len + 1);
156519bb0b8hselasky	if (scheme == NULL) {
156619bb0b8hselasky		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
156719bb0b8hselasky		    errno, "malloc");
156819bb0b8hselasky		return (-1);
156919bb0b8hselasky	}
157019bb0b8hselasky	memcpy(scheme, source, scheme_len);
157119bb0b8hselasky	scheme[scheme_len] = '\0';
157219bb0b8hselasky
157319bb0b8hselasky	/*
157419bb0b8hselasky	 * Treat file: specially - take everything after file:// as
157519bb0b8hselasky	 * the pathname.
157619bb0b8hselasky	 */
157719bb0b8hselasky	if (pcap_strcasecmp(scheme, "file") == 0) {
157819bb0b8hselasky		*schemep = scheme;
157919bb0b8hselasky		*pathp = strdup(colonp + 3);
158019bb0b8hselasky		if (*pathp == NULL) {
158119bb0b8hselasky			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
158219bb0b8hselasky			    errno, "malloc");
158319bb0b8hselasky			return (-1);
158419bb0b8hselasky		}
158519bb0b8hselasky		return (0);
158619bb0b8hselasky	}
158719bb0b8hselasky
158819bb0b8hselasky	/*
158919bb0b8hselasky	 * The WinPcap documentation says you can specify a local
159019bb0b8hselasky	 * interface with "rpcap://{device}"; we special-case
159119bb0b8hselasky	 * that here.  If the scheme is "rpcap", and there are
159219bb0b8hselasky	 * no slashes past the "//", we just return the device.
159319bb0b8hselasky	 *
159419bb0b8hselasky	 * XXX - %-escaping?
159519bb0b8hselasky	 */
159619bb0b8hselasky	if (pcap_strcasecmp(scheme, "rpcap") == 0 &&
159719bb0b8hselasky	    strchr(colonp + 3, '/') == NULL) {
159819bb0b8hselasky		/*
159919bb0b8hselasky		 * Local device.
160019bb0b8hselasky		 *
160119bb0b8hselasky		 * Return a NULL pointer for the scheme, user information,
160219bb0b8hselasky		 * host, and port, and return the device as the path.
160319bb0b8hselasky		 */
160419bb0b8hselasky		free(scheme);
160519bb0b8hselasky		*pathp = strdup(colonp + 3);
160619bb0b8hselasky		if (*pathp == NULL) {
160719bb0b8hselasky			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
160819bb0b8hselasky			    errno, "malloc");
160919bb0b8hselasky			return (-1);
161019bb0b8hselasky		}
161119bb0b8hselasky		return (0);
161219bb0b8hselasky	}
161319bb0b8hselasky
161419bb0b8hselasky	/*
161519bb0b8hselasky	 * OK, now start parsing the authority.
161619bb0b8hselasky	 * Get token, terminated with / or terminated at the end of
161719bb0b8hselasky	 * the string.
161819bb0b8hselasky	 */
161919bb0b8hselasky	authority_len = strcspn(colonp + 3, "/");
162019bb0b8hselasky	authority = get_substring(colonp + 3, authority_len, ebuf);
162119bb0b8hselasky	if (authority == NULL) {
162219bb0b8hselasky		/*
162319bb0b8hselasky		 * Error.
162419bb0b8hselasky		 */
162519bb0b8hselasky		free(scheme);
162619bb0b8hselasky		return (-1);
162719bb0b8hselasky	}
162819bb0b8hselasky	endp = colonp + 3 + authority_len;
162919bb0b8hselasky
163019bb0b8hselasky	/*
163119bb0b8hselasky	 * Now carve the authority field into its components.
163219bb0b8hselasky	 */
163319bb0b8hselasky	parsep = authority;
163419bb0b8hselasky
163519bb0b8hselasky	/*
163619bb0b8hselasky	 * Is there a userinfo field?
163719bb0b8hselasky	 */
163819bb0b8hselasky	atsignp = strchr(parsep, '@');
163919bb0b8hselasky	if (atsignp != NULL) {
164019bb0b8hselasky		/*
164119bb0b8hselasky		 * Yes.
164219bb0b8hselasky		 */
164319bb0b8hselasky		size_t userinfo_len;
164419bb0b8hselasky
164519bb0b8hselasky		userinfo_len = atsignp - parsep;
164619bb0b8hselasky		userinfo = get_substring(parsep, userinfo_len, ebuf);
164719bb0b8hselasky		if (userinfo == NULL) {
164819bb0b8hselasky			/*
164919bb0b8hselasky			 * Error.
165019bb0b8hselasky			 */
165119bb0b8hselasky			free(authority);
165219bb0b8hselasky			free(scheme);
165319bb0b8hselasky			return (-1);
165419bb0b8hselasky		}
165519bb0b8hselasky		parsep = atsignp + 1;
165619bb0b8hselasky	} else {
165719bb0b8hselasky		/*
165819bb0b8hselasky		 * No.
165919bb0b8hselasky		 */
166019bb0b8hselasky		userinfo = NULL;
166119bb0b8hselasky	}
166219bb0b8hselasky
166319bb0b8hselasky	/*
166419bb0b8hselasky	 * Is there a host field?
166519bb0b8hselasky	 */
166619bb0b8hselasky	if (*parsep == '\0') {
166719bb0b8hselasky		/*
166819bb0b8hselasky		 * No; there's no host field or port field.
166919bb0b8hselasky		 */
167019bb0b8hselasky		host = NULL;
167119bb0b8hselasky		port = NULL;
167219bb0b8hselasky	} else {
167319bb0b8hselasky		/*
167419bb0b8hselasky		 * Yes.
167519bb0b8hselasky		 */
167619bb0b8hselasky		size_t host_len;
167719bb0b8hselasky
167819bb0b8hselasky		/*
167919bb0b8hselasky		 * Is it an IP-literal?
168019bb0b8hselasky		 */
168119bb0b8hselasky		if (*parsep == '[') {
168219bb0b8hselasky			/*
168319bb0b8hselasky			 * Yes.
168419bb0b8hselasky			 * Treat verything up to the closing square
168519bb0b8hselasky			 * bracket as the IP-Literal; we don't worry
168619bb0b8hselasky			 * about whether it's a valid IPv6address or
168719bb0b8hselasky			 * IPvFuture.
168819bb0b8hselasky			 */
168919bb0b8hselasky			bracketp = strchr(parsep, ']');
169019bb0b8hselasky			if (bracketp == NULL) {
169119bb0b8hselasky				/*
169219bb0b8hselasky				 * There's no closing square bracket.
169319bb0b8hselasky				 */
169419bb0b8hselasky				pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
169519bb0b8hselasky				    "IP-literal in URL doesn't end with ]");
169619bb0b8hselasky				free(userinfo);
169719bb0b8hselasky				free(authority);
169819bb0b8hselasky				free(scheme);
169919bb0b8hselasky				return (-1);
170019bb0b8hselasky			}
170119bb0b8hselasky			if (*(bracketp + 1) != '\0' &&
170219bb0b8hselasky			    *(bracketp + 1) != ':') {
170319bb0b8hselasky				/*
170419bb0b8hselasky				 * There's extra crud after the
170519bb0b8hselasky				 * closing square bracketn.
170619bb0b8hselasky				 */
170719bb0b8hselasky				pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
170819bb0b8hselasky				    "Extra text after IP-literal in URL");
170919bb0b8hselasky				free(userinfo);
171019bb0b8hselasky				free(authority);
171119bb0b8hselasky				free(scheme);
171219bb0b8hselasky				return (-1);
171319bb0b8hselasky			}
171419bb0b8hselasky			host_len = (bracketp - 1) - parsep;
171519bb0b8hselasky			host = get_substring(parsep + 1, host_len, ebuf);
171619bb0b8hselasky			if (host == NULL) {
171719bb0b8hselasky				/*
171819bb0b8hselasky				 * Error.
171919bb0b8hselasky				 */
172019bb0b8hselasky				free(userinfo);
172119bb0b8hselasky				free(authority);
172219bb0b8hselasky				free(scheme);
172319bb0b8hselasky				return (-1);
172419bb0b8hselasky			}
172519bb0b8hselasky			parsep = bracketp + 1;
172619bb0b8hselasky		} else {
172719bb0b8hselasky			/*
172819bb0b8hselasky			 * No.
172919bb0b8hselasky			 * Treat everything up to a : or the end of
173019bb0b8hselasky			 * the string as the host.
173119bb0b8hselasky			 */
173219bb0b8hselasky			host_len = strcspn(parsep, ":");
173319bb0b8hselasky			host = get_substring(parsep, host_len, ebuf);
173419bb0b8hselasky			if (host == NULL) {
173519bb0b8hselasky				/*
173619bb0b8hselasky				 * Error.
173719bb0b8hselasky				 */
173819bb0b8hselasky				free(userinfo);
173919bb0b8hselasky				free(authority);
174019bb0b8hselasky				free(scheme);
174119bb0b8hselasky				return (-1);
174219bb0b8hselasky			}
174319bb0b8hselasky			parsep = parsep + host_len;
174419bb0b8hselasky		}
174519bb0b8hselasky
174619bb0b8hselasky		/*
174719bb0b8hselasky		 * Is there a port field?
174819bb0b8hselasky		 */
174919bb0b8hselasky		if (*parsep == ':') {
175019bb0b8hselasky			/*
175119bb0b8hselasky			 * Yes.  It's the rest of the authority field.
175219bb0b8hselasky			 */
175319bb0b8hselasky			size_t port_len;
175419bb0b8hselasky
175519bb0b8hselasky			parsep++;
175619bb0b8hselasky			port_len = strlen(parsep);
175719bb0b8hselasky			port = get_substring(parsep, port_len, ebuf);
175819bb0b8hselasky			if (port == NULL) {
175919bb0b8hselasky				/*
176019bb0b8hselasky				 * Error.
176119bb0b8hselasky				 */
176219bb0b8hselasky				free(host);
176319bb0b8hselasky				free(userinfo);
176419bb0b8hselasky				free(authority);
176519bb0b8hselasky				free(scheme);
176619bb0b8hselasky				return (-1);
176719bb0b8hselasky			}
176819bb0b8hselasky		} else {
176919bb0b8hselasky			/*
177019bb0b8hselasky			 * No.
177119bb0b8hselasky			 */
177219bb0b8hselasky			port = NULL;
177319bb0b8hselasky		}
177419bb0b8hselasky	}
177519bb0b8hselasky	free(authority);
177619bb0b8hselasky
177719bb0b8hselasky	/*
177819bb0b8hselasky	 * Everything else is the path.  Strip off the leading /.
177919bb0b8hselasky	 */
178019bb0b8hselasky	if (*endp == '\0')
178119bb0b8hselasky		path = strdup("");
178219bb0b8hselasky	else
178319bb0b8hselasky		path = strdup(endp + 1);
178419bb0b8hselasky	if (path == NULL) {
178519bb0b8hselasky		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
178619bb0b8hselasky		    errno, "malloc");
178719bb0b8hselasky		free(port);
178819bb0b8hselasky		free(host);
178919bb0b8hselasky		free(userinfo);
179019bb0b8hselasky		free(scheme);
179119bb0b8hselasky		return (-1);
179219bb0b8hselasky	}
179319bb0b8hselasky	*schemep = scheme;
179419bb0b8hselasky	*userinfop = userinfo;
179519bb0b8hselasky	*hostp = host;
179619bb0b8hselasky	*portp = port;
179719bb0b8hselasky	*pathp = path;
179819bb0b8hselasky	return (0);
179919bb0b8hselasky}
180019bb0b8hselasky
180119bb0b8hselaskyint
180219bb0b8hselaskypcap_createsrcstr(char *source, int type, const char *host, const char *port,
180319bb0b8hselasky    const char *name, char *errbuf)
180419bb0b8hselasky{
180519bb0b8hselasky	switch (type) {
180619bb0b8hselasky
180719bb0b8hselasky	case PCAP_SRC_FILE:
180819bb0b8hselasky		strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
180919bb0b8hselasky		if (name != NULL && *name != '\0') {
181019bb0b8hselasky			strlcat(source, name, PCAP_BUF_SIZE);
181119bb0b8hselasky			return (0);
181219bb0b8hselasky		} else {
181319bb0b8hselasky			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
181419bb0b8hselasky			    "The file name cannot be NULL.");
181519bb0b8hselasky			return (-1);
181619bb0b8hselasky		}
181719bb0b8hselasky
181819bb0b8hselasky	case PCAP_SRC_IFREMOTE:
181919bb0b8hselasky		strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
182019bb0b8hselasky		if (host != NULL && *host != '\0') {
182119bb0b8hselasky			if (strchr(host, ':') != NULL) {
182219bb0b8hselasky				/*
182319bb0b8hselasky				 * The host name contains a colon, so it's
182419bb0b8hselasky				 * probably an IPv6 address, and needs to
182519bb0b8hselasky				 * be included in square brackets.
182619bb0b8hselasky				 */
182719bb0b8hselasky				strlcat(source, "[", PCAP_BUF_SIZE);
182819bb0b8hselasky				strlcat(source, host, PCAP_BUF_SIZE);
182919bb0b8hselasky				strlcat(source, "]", PCAP_BUF_SIZE);
183019bb0b8hselasky			} else
183119bb0b8hselasky				strlcat(source, host, PCAP_BUF_SIZE);
183219bb0b8hselasky
183319bb0b8hselasky			if (port != NULL && *port != '\0') {
183419bb0b8hselasky				strlcat(source, ":", PCAP_BUF_SIZE);
183519bb0b8hselasky				strlcat(source, port, PCAP_BUF_SIZE);
183619bb0b8hselasky			}
183719bb0b8hselasky
183819bb0b8hselasky			strlcat(source, "/", PCAP_BUF_SIZE);
183919bb0b8hselasky		} else {
184019bb0b8hselasky			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
184119bb0b8hselasky			    "The host name cannot be NULL.");
184219bb0b8hselasky			return (-1);
184319bb0b8hselasky		}
184419bb0b8hselasky
184519bb0b8hselasky		if (name != NULL && *name != '\0')
184619bb0b8hselasky			strlcat(source, name, PCAP_BUF_SIZE);
184719bb0b8hselasky
184819bb0b8hselasky		return (0);
184919bb0b8hselasky
185019bb0b8hselasky	case PCAP_SRC_IFLOCAL:
185119bb0b8hselasky		strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
185219bb0b8hselasky
185319bb0b8hselasky		if (name != NULL && *name != '\0')
185419bb0b8hselasky			strlcat(source, name, PCAP_BUF_SIZE);
185519bb0b8hselasky
185619bb0b8hselasky		return (0);
185719bb0b8hselasky
185819bb0b8hselasky	default:
185919bb0b8hselasky		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
186019bb0b8hselasky		    "The interface type is not valid.");
186119bb0b8hselasky		return (-1);
186219bb0b8hselasky	}
186319bb0b8hselasky}
186419bb0b8hselasky
186519bb0b8hselaskyint
186619bb0b8hselaskypcap_parsesrcstr(const char *source, int *type, char *host, char *port,
186719bb0b8hselasky    char *name, char *errbuf)
186819bb0b8hselasky{
186919bb0b8hselasky	char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
187019bb0b8hselasky
187119bb0b8hselasky	/* Initialization stuff */
187219bb0b8hselasky	if (host)
187319bb0b8hselasky		*host = '\0';
187419bb0b8hselasky	if (port)
187519bb0b8hselasky		*port = '\0';
187619bb0b8hselasky	if (name)
187719bb0b8hselasky		*name = '\0';
187819bb0b8hselasky
187919bb0b8hselasky	/* Parse the source string */
188019bb0b8hselasky	if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
188119bb0b8hselasky	    &tmpport, &tmppath, errbuf) == -1) {
188219bb0b8hselasky		/*
188319bb0b8hselasky		 * Fail.
188419bb0b8hselasky		 */
188519bb0b8hselasky		return (-1);
188619bb0b8hselasky	}
188719bb0b8hselasky
188819bb0b8hselasky	if (scheme == NULL) {
188919bb0b8hselasky		/*
189019bb0b8hselasky		 * Local device.
189119bb0b8hselasky		 */
189219bb0b8hselasky		if (name && tmppath)
189319bb0b8hselasky			strlcpy(name, tmppath, PCAP_BUF_SIZE);
189419bb0b8hselasky		if (type)
189519bb0b8hselasky			*type = PCAP_SRC_IFLOCAL;
189619bb0b8hselasky		free(tmppath);
189719bb0b8hselasky		free(tmpport);
189819bb0b8hselasky		free(tmphost);
189919bb0b8hselasky		free(tmpuserinfo);
190019bb0b8hselasky		return (0);
190119bb0b8hselasky	}
190219bb0b8hselasky
190319bb0b8hselasky	if (strcmp(scheme, "rpcap") == 0) {
190419bb0b8hselasky		/*
190519bb0b8hselasky		 * rpcap://
190619bb0b8hselasky		 *
190719bb0b8hselasky		 * pcap_parse_source() has already handled the case of
190819bb0b8hselasky		 * rpcap://device
190919bb0b8hselasky		 */
191019bb0b8hselasky		if (host && tmphost) {
191119bb0b8hselasky			if (tmpuserinfo)
191219bb0b8hselasky				pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
191319bb0b8hselasky				    tmpuserinfo, tmphost);
191419bb0b8hselasky			else
191519bb0b8hselasky				strlcpy(host, tmphost, PCAP_BUF_SIZE);
191619bb0b8hselasky		}
191719bb0b8hselasky		if (port && tmpport)
191819bb0b8hselasky			strlcpy(port, tmpport, PCAP_BUF_SIZE);
191919bb0b8hselasky		if (name && tmppath)
192019bb0b8hselasky			strlcpy(name, tmppath, PCAP_BUF_SIZE);
192119bb0b8hselasky		if (type)
192219bb0b8hselasky			*type = PCAP_SRC_IFREMOTE;
192319bb0b8hselasky		free(tmppath);
192419bb0b8hselasky		free(tmpport);
192519bb0b8hselasky		free(tmphost);
192619bb0b8hselasky		free(tmpuserinfo);
192719bb0b8hselasky		free(scheme);
192819bb0b8hselasky		return (0);
192919bb0b8hselasky	}
193019bb0b8hselasky
193119bb0b8hselasky	if (strcmp(scheme, "file") == 0) {
193219bb0b8hselasky		/*
193319bb0b8hselasky		 * file://
193419bb0b8hselasky		 */
193519bb0b8hselasky		if (name && tmppath)
193619bb0b8hselasky			strlcpy(name, tmppath, PCAP_BUF_SIZE);
193719bb0b8hselasky		if (type)
193819bb0b8hselasky			*type = PCAP_SRC_FILE;
193919bb0b8hselasky		free(tmppath);
194019bb0b8hselasky		free(tmpport);
194119bb0b8hselasky		free(tmphost);
194219bb0b8hselasky		free(tmpuserinfo);
194319bb0b8hselasky		free(scheme);
194419bb0b8hselasky		return (0);
194519bb0b8hselasky	}
194619bb0b8hselasky
194719bb0b8hselasky	/*
194819bb0b8hselasky	 * Neither rpcap: nor file:; just treat the entire string
194919bb0b8hselasky	 * as a local device.
195019bb0b8hselasky	 */
195119bb0b8hselasky	if (name)
195219bb0b8hselasky		strlcpy(name, source, PCAP_BUF_SIZE);
195319bb0b8hselasky	if (type)
195419bb0b8hselasky		*type = PCAP_SRC_IFLOCAL;
195519bb0b8hselasky	free(tmppath);
195619bb0b8hselasky	free(tmpport);
195719bb0b8hselasky	free(tmphost);
195819bb0b8hselasky	free(tmpuserinfo);
195919bb0b8hselasky	free(scheme);
196019bb0b8hselasky	return (0);
196119bb0b8hselasky}
196219bb0b8hselasky#endif
196319bb0b8hselasky
196419bb0b8hselaskypcap_t *
196519bb0b8hselaskypcap_create(const char *device, char *errbuf)
196619bb0b8hselasky{
196719bb0b8hselasky	size_t i;
196819bb0b8hselasky	int is_theirs;
196919bb0b8hselasky	pcap_t *p;
197019bb0b8hselasky	char *device_str;
197119bb0b8hselasky
197219bb0b8hselasky	/*
197319bb0b8hselasky	 * A null device name is equivalent to the "any" device -
197419bb0b8hselasky	 * which might not be supported on this platform, but
197519bb0b8hselasky	 * this means that you'll get a "not supported" error
197619bb0b8hselasky	 * rather than, say, a crash when we try to dereference
197719bb0b8hselasky	 * the null pointer.
197819bb0b8hselasky	 */
197919bb0b8hselasky	if (device == NULL)
198019bb0b8hselasky		device_str = strdup("any");
198119bb0b8hselasky	else {
198219bb0b8hselasky#ifdef _WIN32
198319bb0b8hselasky		/*
198419bb0b8hselasky		 * If the string appears to be little-endian UCS-2/UTF-16,
198519bb0b8hselasky		 * convert it to ASCII.
198619bb0b8hselasky		 *
198719bb0b8hselasky		 * XXX - to UTF-8 instead?  Or report an error if any
198819bb0b8hselasky		 * character isn't ASCII?
198919bb0b8hselasky		 */
199019bb0b8hselasky		if (device[0] != '\0' && device[1] == '\0') {
199119bb0b8hselasky			size_t length;
199219bb0b8hselasky
199319bb0b8hselasky			length = wcslen((wchar_t *)device);
199419bb0b8hselasky			device_str = (char *)malloc(length + 1);
199519bb0b8hselasky			if (device_str == NULL) {
199619bb0b8hselasky				pcap_fmt_errmsg_for_errno(errbuf,
199719bb0b8hselasky				    PCAP_ERRBUF_SIZE, errno,
199819bb0b8hselasky				    "malloc");
199919bb0b8hselasky				return (NULL);
200019bb0b8hselasky			}
200119bb0b8hselasky
200219bb0b8hselasky			pcap_snprintf(device_str, length + 1, "%ws",
200319bb0b8hselasky			    (const wchar_t *)device);
200419bb0b8hselasky		} else
200519bb0b8hselasky#endif
200619bb0b8hselasky			device_str = strdup(device);
200719bb0b8hselasky	}
200819bb0b8hselasky	if (device_str == NULL) {
200919bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
201019bb0b8hselasky		    errno, "malloc");
201119bb0b8hselasky		return (NULL);
201219bb0b8hselasky	}
201319bb0b8hselasky
201419bb0b8hselasky	/*
201519bb0b8hselasky	 * Try each of the non-local-network-interface capture
201619bb0b8hselasky	 * source types until we find one that works for this
201719bb0b8hselasky	 * device or run out of types.
201819bb0b8hselasky	 */
201919bb0b8hselasky	for (i = 0; capture_source_types[i].create_op != NULL; i++) {
202019bb0b8hselasky		is_theirs = 0;
202119bb0b8hselasky		p = capture_source_types[i].create_op(device_str, errbuf,
202219bb0b8hselasky		    &is_theirs);
202319bb0b8hselasky		if (is_theirs) {
202419bb0b8hselasky			/*
202519bb0b8hselasky			 * The device name refers to a device of the
202619bb0b8hselasky			 * type in question; either it succeeded,
202719bb0b8hselasky			 * in which case p refers to a pcap_t to
202819bb0b8hselasky			 * later activate for the device, or it
202919bb0b8hselasky			 * failed, in which case p is null and we
203019bb0b8hselasky			 * should return that to report the failure
203119bb0b8hselasky			 * to create.
203219bb0b8hselasky			 */
203319bb0b8hselasky			if (p == NULL) {
203419bb0b8hselasky				/*
203519bb0b8hselasky				 * We assume the caller filled in errbuf.
203619bb0b8hselasky				 */
203719bb0b8hselasky				free(device_str);
203819bb0b8hselasky				return (NULL);
203919bb0b8hselasky			}
204019bb0b8hselasky			p->opt.device = device_str;
204119bb0b8hselasky			return (p);
204219bb0b8hselasky		}
204319bb0b8hselasky	}
204419bb0b8hselasky
204519bb0b8hselasky	/*
204619bb0b8hselasky	 * OK, try it as a regular network interface.
204719bb0b8hselasky	 */
204819bb0b8hselasky	p = pcap_create_interface(device_str, errbuf);
204919bb0b8hselasky	if (p == NULL) {
205019bb0b8hselasky		/*
205119bb0b8hselasky		 * We assume the caller filled in errbuf.
205219bb0b8hselasky		 */
205319bb0b8hselasky		free(device_str);
205419bb0b8hselasky		return (NULL);
205519bb0b8hselasky	}
205619bb0b8hselasky	p->opt.device = device_str;
205719bb0b8hselasky	return (p);
205819bb0b8hselasky}
205919bb0b8hselasky
206019bb0b8hselasky/*
206119bb0b8hselasky * Set nonblocking mode on an unactivated pcap_t; this sets a flag
206219bb0b8hselasky * checked by pcap_activate(), which sets the mode after calling
206319bb0b8hselasky * the activate routine.
206419bb0b8hselasky */
206519bb0b8hselaskystatic int
206619bb0b8hselaskypcap_setnonblock_unactivated(pcap_t *p, int nonblock)
206719bb0b8hselasky{
206819bb0b8hselasky	p->opt.nonblock = nonblock;
206919bb0b8hselasky	return (0);
207019bb0b8hselasky}
207119bb0b8hselasky
207219bb0b8hselaskystatic void
207319bb0b8hselaskyinitialize_ops(pcap_t *p)
207419bb0b8hselasky{
207519bb0b8hselasky	/*
207619bb0b8hselasky	 * Set operation pointers for operations that only work on
207719bb0b8hselasky	 * an activated pcap_t to point to a routine that returns
207819bb0b8hselasky	 * a "this isn't activated" error.
207919bb0b8hselasky	 */
208019bb0b8hselasky	p->read_op = (read_op_t)pcap_not_initialized;
208119bb0b8hselasky	p->inject_op = (inject_op_t)pcap_not_initialized;
208219bb0b8hselasky	p->setfilter_op = (setfilter_op_t)pcap_not_initialized;
208319bb0b8hselasky	p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
208419bb0b8hselasky	p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
208519bb0b8hselasky	p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
208619bb0b8hselasky	p->stats_op = (stats_op_t)pcap_not_initialized;
208719bb0b8hselasky#ifdef _WIN32
208819bb0b8hselasky	p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
208919bb0b8hselasky	p->setbuff_op = (setbuff_op_t)pcap_not_initialized;
209019bb0b8hselasky	p->setmode_op = (setmode_op_t)pcap_not_initialized;
209119bb0b8hselasky	p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized;
209219bb0b8hselasky	p->getevent_op = pcap_getevent_not_initialized;
209319bb0b8hselasky	p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized;
209419bb0b8hselasky	p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized;
209519bb0b8hselasky	p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized;
209619bb0b8hselasky	p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized;
209719bb0b8hselasky	p->live_dump_op = (live_dump_op_t)pcap_not_initialized;
209819bb0b8hselasky	p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized;
209919bb0b8hselasky	p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized;
210019bb0b8hselasky#endif
210119bb0b8hselasky
210219bb0b8hselasky	/*
210319bb0b8hselasky	 * Default cleanup operation - implementations can override
210419bb0b8hselasky	 * this, but should call pcap_cleanup_live_common() after
210519bb0b8hselasky	 * doing their own additional cleanup.
210619bb0b8hselasky	 */
210719bb0b8hselasky	p->cleanup_op = pcap_cleanup_live_common;
210819bb0b8hselasky
210919bb0b8hselasky	/*
211019bb0b8hselasky	 * In most cases, the standard one-shot callback can
211119bb0b8hselasky	 * be used for pcap_next()/pcap_next_ex().
211219bb0b8hselasky	 */
211319bb0b8hselasky	p->oneshot_callback = pcap_oneshot;
211419bb0b8hselasky}
211519bb0b8hselasky
211619bb0b8hselaskystatic pcap_t *
211719bb0b8hselaskypcap_alloc_pcap_t(char *ebuf, size_t size)
211819bb0b8hselasky{
211919bb0b8hselasky	char *chunk;
212019bb0b8hselasky	pcap_t *p;
212119bb0b8hselasky
212219bb0b8hselasky	/*
212319bb0b8hselasky	 * Allocate a chunk of memory big enough for a pcap_t
212419bb0b8hselasky	 * plus a structure following it of size "size".  The
212519bb0b8hselasky	 * structure following it is a private data structure
212619bb0b8hselasky	 * for the routines that handle this pcap_t.
212719bb0b8hselasky	 */
212819bb0b8hselasky	chunk = malloc(sizeof (pcap_t) + size);
212919bb0b8hselasky	if (chunk == NULL) {
213019bb0b8hselasky		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
213119bb0b8hselasky		    errno, "malloc");
213219bb0b8hselasky		return (NULL);
213319bb0b8hselasky	}
213419bb0b8hselasky	memset(chunk, 0, sizeof (pcap_t) + size);
213519bb0b8hselasky
213619bb0b8hselasky	/*
213719bb0b8hselasky	 * Get a pointer to the pcap_t at the beginning.
213819bb0b8hselasky	 */
213919bb0b8hselasky	p = (pcap_t *)chunk;
214019bb0b8hselasky
214119bb0b8hselasky#ifdef _WIN32
214219bb0b8hselasky	p->handle = INVALID_HANDLE_VALUE;	/* not opened yet */
214319bb0b8hselasky#else /* _WIN32 */
2144d8d18f6rpaulo	p->fd = -1;	/* not opened yet */
214519bb0b8hselasky#ifndef MSDOS
2146724e1a0rpaulo	p->selectable_fd = -1;
214719bb0b8hselasky	p->required_select_timeout = NULL;
214819bb0b8hselasky#endif /* MSDOS */
214919bb0b8hselasky#endif /* _WIN32 */
2150489abeddelphij
2151489abeddelphij	if (size == 0) {
2152489abeddelphij		/* No private data was requested. */
2153489abeddelphij		p->priv = NULL;
2154489abeddelphij	} else {
2155489abeddelphij		/*
2156489abeddelphij		 * Set the pointer to the private data; that's the structure
2157489abeddelphij		 * of size "size" following the pcap_t.
2158489abeddelphij		 */
2159489abeddelphij		p->priv = (void *)(chunk + sizeof (pcap_t));
2160489abeddelphij	}
2161489abeddelphij
2162489abeddelphij	return (p);
2163489abeddelphij}
2164489abeddelphij
2165489abeddelphijpcap_t *
216694960e5delphijpcap_create_common(char *ebuf, size_t size)
2167489abeddelphij{
2168489abeddelphij	pcap_t *p;
2169489abeddelphij
2170489abeddelphij	p = pcap_alloc_pcap_t(ebuf, size);
2171489abeddelphij	if (p == NULL)
2172489abeddelphij		return (NULL);
2173d8d18f6rpaulo
2174d8d18f6rpaulo	/*
2175d8d18f6rpaulo	 * Default to "can't set rfmon mode"; if it's supported by
2176724e1a0rpaulo	 * a platform, the create routine that called us can set
2177724e1a0rpaulo	 * the op to its routine to check whether a particular
2178724e1a0rpaulo	 * device supports it.
2179d8d18f6rpaulo	 */
2180d8d18f6rpaulo	p->can_set_rfmon_op = pcap_cant_set_rfmon;
2181d8d18f6rpaulo
218219bb0b8hselasky	/*
218319bb0b8hselasky	 * If pcap_setnonblock() is called on a not-yet-activated
218419bb0b8hselasky	 * pcap_t, default to setting a flag and turning
218519bb0b8hselasky	 * on non-blocking mode when activated.
218619bb0b8hselasky	 */
218719bb0b8hselasky	p->setnonblock_op = pcap_setnonblock_unactivated;
218819bb0b8hselasky
2189724e1a0rpaulo	initialize_ops(p);
2190d8d18f6rpaulo
2191d8d18f6rpaulo	/* put in some defaults*/
219219bb0b8hselasky	p->snapshot = 0;		/* max packet size unspecified */
219394960e5delphij	p->opt.timeout = 0;		/* no timeout specified */
219494960e5delphij	p->opt.buffer_size = 0;		/* use the platform's default */
2195d8d18f6rpaulo	p->opt.promisc = 0;
2196489abeddelphij	p->opt.rfmon = 0;
2197489abeddelphij	p->opt.immediate = 0;
2198c5b3ac4gnn	p->opt.tstamp_type = -1;	/* default to not setting time stamp type */
2199489abeddelphij	p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
220019bb0b8hselasky	/*
220119bb0b8hselasky	 * Platform-dependent options.
220219bb0b8hselasky	 */
220319bb0b8hselasky#ifdef __linux__
220419bb0b8hselasky	p->opt.protocol = 0;
220519bb0b8hselasky#endif
220619bb0b8hselasky#ifdef _WIN32
220719bb0b8hselasky	p->opt.nocapture_local = 0;
220819bb0b8hselasky#endif
220994960e5delphij
221094960e5delphij	/*
221194960e5delphij	 * Start out with no BPF code generation flags set.
221294960e5delphij	 */
221394960e5delphij	p->bpf_codegen_flags = 0;
221494960e5delphij
2215d8d18f6rpaulo	return (p);
2216d8d18f6rpaulo}
2217d8d18f6rpaulo
2218d8d18f6rpauloint
2219d8d18f6rpaulopcap_check_activated(pcap_t *p)
2220d8d18f6rpaulo{
2221d8d18f6rpaulo	if (p->activated) {
222294960e5delphij		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
2223d8d18f6rpaulo			" operation on activated capture");
2224c5b3ac4gnn		return (-1);
2225d8d18f6rpaulo	}
2226c5b3ac4gnn	return (0);
2227d8d18f6rpaulo}
2228d8d18f6rpaulo
2229d8d18f6rpauloint
2230d8d18f6rpaulopcap_set_snaplen(pcap_t *p, int snaplen)
2231d8d18f6rpaulo{
2232d8d18f6rpaulo	if (pcap_check_activated(p))
2233c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2234d8d18f6rpaulo	p->snapshot = snaplen;
2235c5b3ac4gnn	return (0);
2236d8d18f6rpaulo}
2237d8d18f6rpaulo
2238d8d18f6rpauloint
2239d8d18f6rpaulopcap_set_promisc(pcap_t *p, int promisc)
2240d8d18f6rpaulo{
2241d8d18f6rpaulo	if (pcap_check_activated(p))
2242c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2243d8d18f6rpaulo	p->opt.promisc = promisc;
2244c5b3ac4gnn	return (0);
2245d8d18f6rpaulo}
2246d8d18f6rpaulo
2247d8d18f6rpauloint
2248d8d18f6rpaulopcap_set_rfmon(pcap_t *p, int rfmon)
2249d8d18f6rpaulo{
2250d8d18f6rpaulo	if (pcap_check_activated(p))
2251c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2252d8d18f6rpaulo	p->opt.rfmon = rfmon;
2253c5b3ac4gnn	return (0);
2254d8d18f6rpaulo}
2255d8d18f6rpaulo
2256d8d18f6rpauloint
2257d8d18f6rpaulopcap_set_timeout(pcap_t *p, int timeout_ms)
2258f0fdf33pst{
2259d8d18f6rpaulo	if (pcap_check_activated(p))
2260c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2261489abeddelphij	p->opt.timeout = timeout_ms;
2262c5b3ac4gnn	return (0);
2263c5b3ac4gnn}
2264c5b3ac4gnn
2265c5b3ac4gnnint
2266c5b3ac4gnnpcap_set_tstamp_type(pcap_t *p, int tstamp_type)
2267c5b3ac4gnn{
2268c5b3ac4gnn	int i;
2269c5b3ac4gnn
2270c5b3ac4gnn	if (pcap_check_activated(p))
2271c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2272c5b3ac4gnn
2273c5b3ac4gnn	/*
227494960e5delphij	 * The argument should have been u_int, but that's too late
227594960e5delphij	 * to change now - it's an API.
227694960e5delphij	 */
227794960e5delphij	if (tstamp_type < 0)
227894960e5delphij		return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
227994960e5delphij
228094960e5delphij	/*
2281489abeddelphij	 * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST;
2282489abeddelphij	 * the default time stamp type is PCAP_TSTAMP_HOST.
2283c5b3ac4gnn	 */
2284489abeddelphij	if (p->tstamp_type_count == 0) {
2285489abeddelphij		if (tstamp_type == PCAP_TSTAMP_HOST) {
2286c5b3ac4gnn			p->opt.tstamp_type = tstamp_type;
2287c5b3ac4gnn			return (0);
2288c5b3ac4gnn		}
2289489abeddelphij	} else {
2290489abeddelphij		/*
2291489abeddelphij		 * Check whether we claim to support this type of time stamp.
2292489abeddelphij		 */
2293489abeddelphij		for (i = 0; i < p->tstamp_type_count; i++) {
229494960e5delphij			if (p->tstamp_type_list[i] == (u_int)tstamp_type) {
2295489abeddelphij				/*
2296489abeddelphij				 * Yes.
2297489abeddelphij				 */
2298489abeddelphij				p->opt.tstamp_type = tstamp_type;
2299489abeddelphij				return (0);
2300489abeddelphij			}
2301489abeddelphij		}
2302c5b3ac4gnn	}
2303c5b3ac4gnn
2304c5b3ac4gnn	/*
2305489abeddelphij	 * We don't support this type of time stamp.
2306c5b3ac4gnn	 */
2307c5b3ac4gnn	return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
2308d8d18f6rpaulo}
2309d8d18f6rpaulo
2310d8d18f6rpauloint
2311489abeddelphijpcap_set_immediate_mode(pcap_t *p, int immediate)
2312489abeddelphij{
2313489abeddelphij	if (pcap_check_activated(p))
2314489abeddelphij		return (PCAP_ERROR_ACTIVATED);
2315489abeddelphij	p->opt.immediate = immediate;
2316489abeddelphij	return (0);
2317489abeddelphij}
2318489abeddelphij
2319489abeddelphijint
2320d8d18f6rpaulopcap_set_buffer_size(pcap_t *p, int buffer_size)
2321d8d18f6rpaulo{
2322d8d18f6rpaulo	if (pcap_check_activated(p))
2323c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
232494960e5delphij	if (buffer_size <= 0) {
232594960e5delphij		/*
232694960e5delphij		 * Silently ignore invalid values.
232794960e5delphij		 */
232894960e5delphij		return (0);
232994960e5delphij	}
2330d8d18f6rpaulo	p->opt.buffer_size = buffer_size;
2331c5b3ac4gnn	return (0);
2332d8d18f6rpaulo}
2333d8d18f6rpaulo
2334d8d18f6rpauloint
2335489abeddelphijpcap_set_tstamp_precision(pcap_t *p, int tstamp_precision)
2336489abeddelphij{
2337489abeddelphij	int i;
2338489abeddelphij
2339489abeddelphij	if (pcap_check_activated(p))
2340489abeddelphij		return (PCAP_ERROR_ACTIVATED);
2341489abeddelphij
2342489abeddelphij	/*
234394960e5delphij	 * The argument should have been u_int, but that's too late
234494960e5delphij	 * to change now - it's an API.
234594960e5delphij	 */
234694960e5delphij	if (tstamp_precision < 0)
234794960e5delphij		return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP);
234894960e5delphij
234994960e5delphij	/*
2350489abeddelphij	 * If p->tstamp_precision_count is 0, we only support setting
2351489abeddelphij	 * the time stamp precision to microsecond precision; every
2352489abeddelphij	 * pcap module *MUST* support microsecond precision, even if
2353489abeddelphij	 * it does so by converting the native precision to
2354489abeddelphij	 * microseconds.
2355489abeddelphij	 */
2356489abeddelphij	if (p->tstamp_precision_count == 0) {
2357489abeddelphij		if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) {
2358489abeddelphij			p->opt.tstamp_precision = tstamp_precision;
2359489abeddelphij			return (0);
2360489abeddelphij		}
2361489abeddelphij	} else {
2362489abeddelphij		/*
2363489abeddelphij		 * Check whether we claim to support this precision of
2364489abeddelphij		 * time stamp.
2365489abeddelphij		 */
2366489abeddelphij		for (i = 0; i < p->tstamp_precision_count; i++) {
236794960e5delphij			if (p->tstamp_precision_list[i] == (u_int)tstamp_precision) {
2368489abeddelphij				/*
2369489abeddelphij				 * Yes.
2370489abeddelphij				 */
2371489abeddelphij				p->opt.tstamp_precision = tstamp_precision;
2372489abeddelphij				return (0);
2373489abeddelphij			}
2374489abeddelphij		}
2375489abeddelphij	}
2376489abeddelphij
2377489abeddelphij	/*
2378489abeddelphij	 * We don't support this time stamp precision.
2379489abeddelphij	 */
2380489abeddelphij	return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP);
2381489abeddelphij}
2382489abeddelphij
2383489abeddelphijint
2384489abeddelphijpcap_get_tstamp_precision(pcap_t *p)
2385489abeddelphij{
2386489abeddelphij        return (p->opt.tstamp_precision);
2387489abeddelphij}
2388489abeddelphij
2389489abeddelphijint
2390d8d18f6rpaulopcap_activate(pcap_t *p)
2391d8d18f6rpaulo{
2392d8d18f6rpaulo	int status;
2393f0fdf33pst
2394c5b3ac4gnn	/*
2395c5b3ac4gnn	 * Catch attempts to re-activate an already-activated
2396c5b3ac4gnn	 * pcap_t; this should, for example, catch code that
2397c5b3ac4gnn	 * calls pcap_open_live() followed by pcap_activate(),
2398c5b3ac4gnn	 * as some code that showed up in a Stack Exchange
2399c5b3ac4gnn	 * question did.
2400c5b3ac4gnn	 */
2401c5b3ac4gnn	if (pcap_check_activated(p))
2402c5b3ac4gnn		return (PCAP_ERROR_ACTIVATED);
2403d8d18f6rpaulo	status = p->activate_op(p);
240419bb0b8hselasky	if (status >= 0) {
240519bb0b8hselasky		/*
240619bb0b8hselasky		 * If somebody requested non-blocking mode before
240719bb0b8hselasky		 * calling pcap_activate(), turn it on now.
240819bb0b8hselasky		 */
240919bb0b8hselasky		if (p->opt.nonblock) {
241019bb0b8hselasky			status = p->setnonblock_op(p, 1);
241119bb0b8hselasky			if (status < 0) {
241219bb0b8hselasky				/*
241319bb0b8hselasky				 * Failed.  Undo everything done by
241419bb0b8hselasky				 * the activate operation.
241519bb0b8hselasky				 */
241619bb0b8hselasky				p->cleanup_op(p);
241719bb0b8hselasky				initialize_ops(p);
241819bb0b8hselasky				return (status);
241919bb0b8hselasky			}
242019bb0b8hselasky		}
2421d8d18f6rpaulo		p->activated = 1;
242219bb0b8hselasky	} else {
2423724e1a0rpaulo		if (p->errbuf[0] == '\0') {
2424724e1a0rpaulo			/*
2425724e1a0rpaulo			 * No error message supplied by the activate routine;
2426724e1a0rpaulo			 * for the benefit of programs that don't specially
2427724e1a0rpaulo			 * handle errors other than PCAP_ERROR, return the
2428724e1a0rpaulo			 * error message corresponding to the status.
2429724e1a0rpaulo			 */
243094960e5delphij			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
2431724e1a0rpaulo			    pcap_statustostr(status));
2432724e1a0rpaulo		}
2433724e1a0rpaulo
2434724e1a0rpaulo		/*
2435724e1a0rpaulo		 * Undo any operation pointer setting, etc. done by
2436724e1a0rpaulo		 * the activate operation.
2437724e1a0rpaulo		 */
2438724e1a0rpaulo		initialize_ops(p);
2439724e1a0rpaulo	}
2440d8d18f6rpaulo	return (status);
2441d8d18f6rpaulo}
2442d8d18f6rpaulo
2443d8d18f6rpaulopcap_t *
244494960e5delphijpcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf)
2445d8d18f6rpaulo{
2446d8d18f6rpaulo	pcap_t *p;
2447d8d18f6rpaulo	int status;
244819bb0b8hselasky#ifdef ENABLE_REMOTE
244919bb0b8hselasky	char host[PCAP_BUF_SIZE + 1];
245019bb0b8hselasky	char port[PCAP_BUF_SIZE + 1];
245119bb0b8hselasky	char name[PCAP_BUF_SIZE + 1];
245219bb0b8hselasky	int srctype;
245319bb0b8hselasky
245419bb0b8hselasky	/*
245519bb0b8hselasky	 * Retrofit - we have to make older applications compatible with
245619bb0b8hselasky	 * remote capture.
245719bb0b8hselasky	 * So we're calling pcap_open_remote() from here; this is a very
245819bb0b8hselasky	 * dirty hack.
245919bb0b8hselasky	 * Obviously, we cannot exploit all the new features; for instance,
246019bb0b8hselasky	 * we cannot send authentication, we cannot use a UDP data connection,
246119bb0b8hselasky	 * and so on.
246219bb0b8hselasky	 */
246319bb0b8hselasky	if (pcap_parsesrcstr(device, &srctype, host, port, name, errbuf))
246419bb0b8hselasky		return (NULL);
246519bb0b8hselasky
246619bb0b8hselasky	if (srctype == PCAP_SRC_IFREMOTE) {
246719bb0b8hselasky		/*
246819bb0b8hselasky		 * Although we already have host, port and iface, we prefer
246919bb0b8hselasky		 * to pass only 'device' to pcap_open_rpcap(), so that it has
247019bb0b8hselasky		 * to call pcap_parsesrcstr() again.
247119bb0b8hselasky		 * This is less optimized, but much clearer.
247219bb0b8hselasky		 */
247319bb0b8hselasky		return (pcap_open_rpcap(device, snaplen,
247419bb0b8hselasky		    promisc ? PCAP_OPENFLAG_PROMISCUOUS : 0, to_ms,
247519bb0b8hselasky		    NULL, errbuf));
247619bb0b8hselasky	}
247719bb0b8hselasky	if (srctype == PCAP_SRC_FILE) {
247819bb0b8hselasky		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
247919bb0b8hselasky		return (NULL);
248019bb0b8hselasky	}
248119bb0b8hselasky	if (srctype == PCAP_SRC_IFLOCAL) {
248219bb0b8hselasky		/*
248319bb0b8hselasky		 * If it starts with rpcap://, that refers to a local device
248419bb0b8hselasky		 * (no host part in the URL). Remove the rpcap://, and
248519bb0b8hselasky		 * fall through to the regular open path.
248619bb0b8hselasky		 */
248719bb0b8hselasky		if (strncmp(device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) {
248819bb0b8hselasky			size_t len = strlen(device) - strlen(PCAP_SRC_IF_STRING) + 1;
248919bb0b8hselasky
249019bb0b8hselasky			if (len > 0)
249119bb0b8hselasky				device += strlen(PCAP_SRC_IF_STRING);
249219bb0b8hselasky		}
249319bb0b8hselasky	}
249419bb0b8hselasky#endif	/* ENABLE_REMOTE */
2495d8d18f6rpaulo
249694960e5delphij	p = pcap_create(device, errbuf);
2497d8d18f6rpaulo	if (p == NULL)
2498d8d18f6rpaulo		return (NULL);
2499d8d18f6rpaulo	status = pcap_set_snaplen(p, snaplen);
2500d8d18f6rpaulo	if (status < 0)
2501d8d18f6rpaulo		goto fail;
2502d8d18f6rpaulo	status = pcap_set_promisc(p, promisc);
2503d8d18f6rpaulo	if (status < 0)
2504d8d18f6rpaulo		goto fail;
2505d8d18f6rpaulo	status = pcap_set_timeout(p, to_ms);
2506d8d18f6rpaulo	if (status < 0)
2507d8d18f6rpaulo		goto fail;
2508d8d18f6rpaulo	/*
2509d8d18f6rpaulo	 * Mark this as opened with pcap_open_live(), so that, for
2510d8d18f6rpaulo	 * example, we show the full list of DLT_ values, rather
2511d8d18f6rpaulo	 * than just the ones that are compatible with capturing
2512d8d18f6rpaulo	 * when not in monitor mode.  That allows existing applications
2513d8d18f6rpaulo	 * to work the way they used to work, but allows new applications
2514d8d18f6rpaulo	 * that know about the new open API to, for example, find out the
2515d8d18f6rpaulo	 * DLT_ values that they can select without changing whether
2516d8d18f6rpaulo	 * the adapter is in monitor mode or not.
2517d8d18f6rpaulo	 */
2518d8d18f6rpaulo	p->oldstyle = 1;
2519d8d18f6rpaulo	status = pcap_activate(p);
2520d8d18f6rpaulo	if (status < 0)
2521d8d18f6rpaulo		goto fail;
2522d8d18f6rpaulo	return (p);
2523d8d18f6rpaulofail:
2524724e1a0rpaulo	if (status == PCAP_ERROR)
252594960e5delphij		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
2526724e1a0rpaulo		    p->errbuf);
2527724e1a0rpaulo	else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
2528c5b3ac4gnn	    status == PCAP_ERROR_PERM_DENIED ||
2529c5b3ac4gnn	    status == PCAP_ERROR_PROMISC_PERM_DENIED)
253094960e5delphij		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", device,
2531724e1a0rpaulo		    pcap_statustostr(status), p->errbuf);
2532d8d18f6rpaulo	else
253394960e5delphij		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
2534d8d18f6rpaulo		    pcap_statustostr(status));
2535d8d18f6rpaulo	pcap_close(p);
2536d8d18f6rpaulo	return (NULL);
2537d8d18f6rpaulo}
2538d8d18f6rpaulo
2539489abeddelphijpcap_t *
2540489abeddelphijpcap_open_offline_common(char *ebuf, size_t size)
2541489abeddelphij{
2542489abeddelphij	pcap_t *p;
2543489abeddelphij
2544489abeddelphij	p = pcap_alloc_pcap_t(ebuf, size);
2545489abeddelphij	if (p == NULL)
2546489abeddelphij		return (NULL);
2547489abeddelphij
2548489abeddelphij	p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
2549489abeddelphij
2550489abeddelphij	return (p);
2551489abeddelphij}
2552489abeddelphij
2553d8d18f6rpauloint
2554d8d18f6rpaulopcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
2555d8d18f6rpaulo{
2556c5b3ac4gnn	return (p->read_op(p, cnt, callback, user));
2557da13a5abms}
2558da13a5abms
2559f0fdf33pstint
2560f0fdf33pstpcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
2561f0fdf33pst{
2562ca0d84cfenner	register int n;
2563ca0d84cfenner
2564f0fdf33pst	for (;;) {
2565489abeddelphij		if (p->rfile != NULL) {
2566da13a5abms			/*
2567da13a5abms			 * 0 means EOF, so don't loop if we get 0.
2568da13a5abms			 */
2569ca0d84cfenner			n = pcap_offline_read(p, cnt, callback, user);
2570da13a5abms		} else {
2571ca0d84cfenner			/*
2572ca0d84cfenner			 * XXX keep reading until we get something
2573ca0d84cfenner			 * (or an error occurs)
2574ca0d84cfenner			 */
2575ca0d84cfenner			do {
2576da13a5abms				n = p->read_op(p, cnt, callback, user);
2577ca0d84cfenner			} while (n == 0);
2578ca0d84cfenner		}
2579f0fdf33pst		if (n <= 0)
2580f0fdf33pst			return (n);
2581489abeddelphij		if (!PACKET_COUNT_IS_UNLIMITED(cnt)) {
2582f0fdf33pst			cnt -= n;
2583f0fdf33pst			if (cnt <= 0)
2584f0fdf33pst				return (0);
2585f0fdf33pst		}
2586f0fdf33pst	}
2587f0fdf33pst}
2588f0fdf33pst
2589da13a5abms/*
2590da13a5abms * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate.
2591da13a5abms */
2592da13a5abmsvoid
2593da13a5abmspcap_breakloop(pcap_t *p)
2594da13a5abms{
2595da13a5abms	p->break_loop = 1;
2596da13a5abms}
2597da13a5abms
2598f0fdf33pstint
2599f0fdf33pstpcap_datalink(pcap_t *p)
2600f0fdf33pst{
2601489abeddelphij	if (!p->activated)
2602489abeddelphij		return (PCAP_ERROR_NOT_ACTIVATED);
2603f0fdf33pst	return (p->linktype);
2604f0fdf33pst}
2605f0fdf33pst
2606f0fdf33pstint
2607d8d18f6rpaulopcap_datalink_ext(pcap_t *p)
2608d8d18f6rpaulo{
2609489abeddelphij	if (!p->activated)
2610489abeddelphij		return (PCAP_ERROR_NOT_ACTIVATED);
2611d8d18f6rpaulo	return (p->linktype_ext);
2612d8d18f6rpaulo}
2613d8d18f6rpaulo
2614d8d18f6rpauloint
261534111fdfennerpcap_list_datalinks(pcap_t *p, int **dlt_buffer)
261634111fdfenner{
2617489abeddelphij	if (!p->activated)
2618489abeddelphij		return (PCAP_ERROR_NOT_ACTIVATED);
2619da13a5abms	if (p->dlt_count == 0) {
2620da13a5abms		/*
2621da13a5abms		 * We couldn't fetch the list of DLTs, which means
2622da13a5abms		 * this platform doesn't support changing the
2623da13a5abms		 * DLT for an interface.  Return a list of DLTs
2624da13a5abms		 * containing only the DLT this device supports.
2625da13a5abms		 */
2626da13a5abms		*dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
2627da13a5abms		if (*dlt_buffer == NULL) {
262819bb0b8hselasky			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
262919bb0b8hselasky			    errno, "malloc");
2630489abeddelphij			return (PCAP_ERROR);
2631da13a5abms		}
2632da13a5abms		**dlt_buffer = p->linktype;
2633da13a5abms		return (1);
2634da13a5abms	} else {
26354462427mlaier		*dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
2636da13a5abms		if (*dlt_buffer == NULL) {
263719bb0b8hselasky			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
263819bb0b8hselasky			    errno, "malloc");
2639489abeddelphij			return (PCAP_ERROR);
2640da13a5abms		}
2641da13a5abms		(void)memcpy(*dlt_buffer, p->dlt_list,
2642da13a5abms		    sizeof(**dlt_buffer) * p->dlt_count);
2643da13a5abms		return (p->dlt_count);
264434111fdfenner	}
2645da13a5abms}
2646da13a5abms
2647d8d18f6rpaulo/*
2648d8d18f6rpaulo * In Windows, you might have a library built with one version of the
2649d8d18f6rpaulo * C runtime library and an application built with another version of
2650d8d18f6rpaulo * the C runtime library, which means that the library might use one
2651d8d18f6rpaulo * version of malloc() and free() and the application might use another
2652d8d18f6rpaulo * version of malloc() and free().  If so, that means something
2653d8d18f6rpaulo * allocated by the library cannot be freed by the application, so we
2654d8d18f6rpaulo * need to have a pcap_free_datalinks() routine to free up the list
2655d8d18f6rpaulo * allocated by pcap_list_datalinks(), even though it's just a wrapper
2656d8d18f6rpaulo * around free().
2657d8d18f6rpaulo */
2658d8d18f6rpaulovoid
2659d8d18f6rpaulopcap_free_datalinks(int *dlt_list)
2660d8d18f6rpaulo{
2661d8d18f6rpaulo	free(dlt_list);
2662d8d18f6rpaulo}
2663d8d18f6rpaulo
2664da13a5abmsint
2665da13a5abmspcap_set_datalink(pcap_t *p, int dlt)
2666da13a5abms{
2667da13a5abms	int i;
2668da13a5abms	const char *dlt_name;
2669da13a5abms
267094960e5delphij	if (dlt < 0)
267194960e5delphij		goto unsupported;
267294960e5delphij
2673da13a5abms	if (p->dlt_count == 0 || p->set_datalink_op == NULL) {
2674da13a5abms		/*
2675da13a5abms		 * We couldn't fetch the list of DLTs, or we don't
2676da13a5abms		 * have a "set datalink" operation, which means
2677da13a5abms		 * this platform doesn't support changing the
2678da13a5abms		 * DLT for an interface.  Check whether the new
2679da13a5abms		 * DLT is the one this interface supports.
2680da13a5abms		 */
2681da13a5abms		if (p->linktype != dlt)
2682da13a5abms			goto unsupported;
2683da13a5abms
2684da13a5abms		/*
2685da13a5abms		 * It is, so there's nothing we need to do here.
2686da13a5abms		 */
2687da13a5abms		return (0);
2688da13a5abms	}
2689da13a5abms	for (i = 0; i < p->dlt_count; i++)
269094960e5delphij		if (p->dlt_list[i] == (u_int)dlt)
2691da13a5abms			break;
2692da13a5abms	if (i >= p->dlt_count)
2693da13a5abms		goto unsupported;
269470f7ae4sam	if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB &&
269570f7ae4sam	    dlt == DLT_DOCSIS) {
269670f7ae4sam		/*
269770f7ae4sam		 * This is presumably an Ethernet device, as the first
269870f7ae4sam		 * link-layer type it offers is DLT_EN10MB, and the only
269970f7ae4sam		 * other type it offers is DLT_DOCSIS.  That means that
270070f7ae4sam		 * we can't tell the driver to supply DOCSIS link-layer
270170f7ae4sam		 * headers - we're just pretending that's what we're
270270f7ae4sam		 * getting, as, presumably, we're capturing on a dedicated
270370f7ae4sam		 * link to a Cisco Cable Modem Termination System, and
270470f7ae4sam		 * it's putting raw DOCSIS frames on the wire inside low-level
270570f7ae4sam		 * Ethernet framing.
270670f7ae4sam		 */
270770f7ae4sam		p->linktype = dlt;
270870f7ae4sam		return (0);
270970f7ae4sam	}
2710da13a5abms	if (p->set_datalink_op(p, dlt) == -1)
2711da13a5abms		return (-1);
2712da13a5abms	p->linktype = dlt;
2713da13a5abms	return (0);
2714da13a5abms
2715da13a5abmsunsupported:
2716da13a5abms	dlt_name = pcap_datalink_val_to_name(dlt);
2717da13a5abms	if (dlt_name != NULL) {
271894960e5delphij		(void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
2719da13a5abms		    "%s is not one of the DLTs supported by this device",
2720da13a5abms		    dlt_name);
2721da13a5abms	} else {
272294960e5delphij		(void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
2723da13a5abms		    "DLT %d is not one of the DLTs supported by this device",
2724da13a5abms		    dlt);
2725da13a5abms	}
2726da13a5abms	return (-1);
2727da13a5abms}
2728da13a5abms
2729c5b3ac4gnn/*
2730c5b3ac4gnn * This array is designed for mapping upper and lower case letter
2731c5b3ac4gnn * together for a case independent comparison.  The mappings are
2732c5b3ac4gnn * based upon ascii character sequences.
2733c5b3ac4gnn */
2734c5b3ac4gnnstatic const u_char charmap[] = {
2735c5b3ac4gnn	(u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
2736c5b3ac4gnn	(u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
2737c5b3ac4gnn	(u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
2738c5b3ac4gnn	(u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
2739c5b3ac4gnn	(u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
2740c5b3ac4gnn	(u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
2741c5b3ac4gnn	(u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
2742c5b3ac4gnn	(u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
2743c5b3ac4gnn	(u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
2744c5b3ac4gnn	(u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
2745c5b3ac4gnn	(u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
2746c5b3ac4gnn	(u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
2747c5b3ac4gnn	(u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
2748c5b3ac4gnn	(u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
2749c5b3ac4gnn	(u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
2750c5b3ac4gnn	(u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
2751c5b3ac4gnn	(u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
2752c5b3ac4gnn	(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
2753c5b3ac4gnn	(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
2754c5b3ac4gnn	(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
2755c5b3ac4gnn	(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
2756c5b3ac4gnn	(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
2757c5b3ac4gnn	(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
2758c5b3ac4gnn	(u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
2759c5b3ac4gnn	(u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
2760c5b3ac4gnn	(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
2761c5b3ac4gnn	(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
2762c5b3ac4gnn	(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
2763c5b3ac4gnn	(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
2764c5b3ac4gnn	(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
2765c5b3ac4gnn	(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
2766c5b3ac4gnn	(u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
2767c5b3ac4gnn	(u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
2768c5b3ac4gnn	(u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
2769c5b3ac4gnn	(u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
2770c5b3ac4gnn	(u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
2771c5b3ac4gnn	(u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
2772c5b3ac4gnn	(u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
2773c5b3ac4gnn	(u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
2774c5b3ac4gnn	(u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
2775c5b3ac4gnn	(u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
2776c5b3ac4gnn	(u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
2777c5b3ac4gnn	(u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
2778c5b3ac4gnn	(u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
2779c5b3ac4gnn	(u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
2780c5b3ac4gnn	(u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
2781c5b3ac4gnn	(u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
2782c5b3ac4gnn	(u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
2783c5b3ac4gnn	(u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
2784c5b3ac4gnn	(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
2785c5b3ac4gnn	(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
2786c5b3ac4gnn	(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
2787c5b3ac4gnn	(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
2788c5b3ac4gnn	(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
2789c5b3ac4gnn	(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
2790c5b3ac4gnn	(u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
2791c5b3ac4gnn	(u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
2792c5b3ac4gnn	(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
2793c5b3ac4gnn	(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
2794c5b3ac4gnn	(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
2795c5b3ac4gnn	(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
2796c5b3ac4gnn	(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
2797c5b3ac4gnn	(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
2798c5b3ac4gnn	(u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
2799c5b3ac4gnn};
2800c5b3ac4gnn
2801c5b3ac4gnnint
2802c5b3ac4gnnpcap_strcasecmp(const char *s1, const char *s2)
2803c5b3ac4gnn{
2804c5b3ac4gnn	register const u_char	*cm = charmap,
2805c5b3ac4gnn				*us1 = (const u_char *)s1,
2806c5b3ac4gnn				*us2 = (const u_char *)s2;
2807c5b3ac4gnn
2808c5b3ac4gnn	while (cm[*us1] == cm[*us2++])
2809c5b3ac4gnn		if (*us1++ == '\0')
2810c5b3ac4gnn			return(0);
2811c5b3ac4gnn	return (cm[*us1] - cm[*--us2]);
2812c5b3ac4gnn}
2813c5b3ac4gnn
2814da13a5abmsstruct dlt_choice {
2815da13a5abms	const char *name;
2816da13a5abms	const char *description;
2817da13a5abms	int	dlt;
2818da13a5abms};
2819da13a5abms
282094960e5delphij#define DLT_CHOICE(code, description) { #code, description, DLT_ ## code }
2821da13a5abms#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
2822da13a5abms
2823da13a5abmsstatic struct dlt_choice dlt_choices[] = {
282494960e5delphij	DLT_CHOICE(NULL, "BSD loopback"),
282594960e5delphij	DLT_CHOICE(EN10MB, "Ethernet"),
282694960e5delphij	DLT_CHOICE(IEEE802, "Token ring"),
282794960e5delphij	DLT_CHOICE(ARCNET, "BSD ARCNET"),
282894960e5delphij	DLT_CHOICE(SLIP, "SLIP"),
282994960e5delphij	DLT_CHOICE(PPP, "PPP"),
283094960e5delphij	DLT_CHOICE(FDDI, "FDDI"),
283194960e5delphij	DLT_CHOICE(ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"),
283294960e5delphij	DLT_CHOICE(RAW, "Raw IP"),
283394960e5delphij	DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"),
283494960e5delphij	DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"),
283594960e5delphij	DLT_CHOICE(ATM_CLIP, "Linux Classical IP-over-ATM"),
283694960e5delphij	DLT_CHOICE(PPP_SERIAL, "PPP over serial"),
283794960e5delphij	DLT_CHOICE(PPP_ETHER, "PPPoE"),
283894960e5delphij	DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"),
283994960e5delphij	DLT_CHOICE(C_HDLC, "Cisco HDLC"),
284094960e5delphij	DLT_CHOICE(IEEE802_11, "802.11"),
284194960e5delphij	DLT_CHOICE(FRELAY, "Frame Relay"),
284294960e5delphij	DLT_CHOICE(LOOP, "OpenBSD loopback"),
284394960e5delphij	DLT_CHOICE(ENC, "OpenBSD encapsulated IP"),
284494960e5delphij	DLT_CHOICE(LINUX_SLL, "Linux cooked"),
284594960e5delphij	DLT_CHOICE(LTALK, "Localtalk"),
284694960e5delphij	DLT_CHOICE(PFLOG, "OpenBSD pflog file"),
284794960e5delphij	DLT_CHOICE(PFSYNC, "Packet filter state syncing"),
284894960e5delphij	DLT_CHOICE(PRISM_HEADER, "802.11 plus Prism header"),
284994960e5delphij	DLT_CHOICE(IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"),
285094960e5delphij	DLT_CHOICE(SUNATM, "Sun raw ATM"),
285194960e5delphij	DLT_CHOICE(IEEE802_11_RADIO, "802.11 plus radiotap header"),
285294960e5delphij	DLT_CHOICE(ARCNET_LINUX, "Linux ARCNET"),
285394960e5delphij	DLT_CHOICE(JUNIPER_MLPPP, "Juniper Multi-Link PPP"),
285494960e5delphij	DLT_CHOICE(JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"),
285594960e5delphij	DLT_CHOICE(JUNIPER_ES, "Juniper Encryption Services PIC"),
285694960e5delphij	DLT_CHOICE(JUNIPER_GGSN, "Juniper GGSN PIC"),
285794960e5delphij	DLT_CHOICE(JUNIPER_MFR, "Juniper FRF.16 Frame Relay"),
285894960e5delphij	DLT_CHOICE(JUNIPER_ATM2, "Juniper ATM2 PIC"),
285994960e5delphij	DLT_CHOICE(JUNIPER_SERVICES, "Juniper Advanced Services PIC"),
286094960e5delphij	DLT_CHOICE(JUNIPER_ATM1, "Juniper ATM1 PIC"),
286194960e5delphij	DLT_CHOICE(APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"),
286294960e5delphij	DLT_CHOICE(MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"),
286394960e5delphij	DLT_CHOICE(MTP2, "SS7 MTP2"),
286494960e5delphij	DLT_CHOICE(MTP3, "SS7 MTP3"),
286594960e5delphij	DLT_CHOICE(SCCP, "SS7 SCCP"),
286694960e5delphij	DLT_CHOICE(DOCSIS, "DOCSIS"),
286794960e5delphij	DLT_CHOICE(LINUX_IRDA, "Linux IrDA"),
286894960e5delphij	DLT_CHOICE(IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"),
286994960e5delphij	DLT_CHOICE(JUNIPER_MONITOR, "Juniper Passive Monitor PIC"),
287094960e5delphij	DLT_CHOICE(BACNET_MS_TP, "BACnet MS/TP"),
287194960e5delphij	DLT_CHOICE(PPP_PPPD, "PPP for pppd, with direction flag"),
287294960e5delphij	DLT_CHOICE(