*/
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.77 2002-02-10 00:05:14 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.78 2002-02-22 09:20:11 guy Exp $ (LBL)";
#endif
/*
{
pcap_t *handle;
int mtu;
+ int err;
+ int live_open_ok = 0;
struct utsname utsname;
/* Allocate a handle for this session. */
* trying both methods with the newer method preferred.
*/
- if (! (live_open_new(handle, device, promisc, to_ms, ebuf) ||
- live_open_old(handle, device, promisc, to_ms, ebuf)) )
- {
+ if ((err = live_open_new(handle, device, promisc, to_ms, ebuf)) == 1)
+ live_open_ok = 1;
+ else if (err == 0) {
+ /* Non-fatal error; try old way */
+ if (live_open_old(handle, device, promisc, to_ms, ebuf))
+ live_open_ok = 1;
+ }
+ if (!live_open_ok) {
/*
* Both methods to open the packet socket failed. Tidy
* up and report our failure (ebuf is expected to be
* set by the functions above).
*/
- free(handle->md.device);
+ if (handle->md.device != NULL)
+ free(handle->md.device);
free(handle);
return NULL;
}
*/
mtu = iface_get_mtu(handle->fd, device, ebuf);
if (mtu == -1) {
+ if (handle->md.clear_promisc)
+ /* 2.0.x kernel */
+ pcap_close_linux(handle);
close(handle->fd);
- free(handle->md.device);
+ if (handle->md.device != NULL)
+ free(handle->md.device);
free(handle);
return NULL;
}
if (!handle->buffer) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
+ if (handle->md.clear_promisc)
+ /* 2.0.x kernel */
+ pcap_close_linux(handle);
close(handle->fd);
- free(handle->md.device);
+ if (handle->md.device != NULL)
+ free(handle->md.device);
free(handle);
return NULL;
}
#ifdef SO_ATTACH_FILTER
struct sock_fprog fcode;
int can_filter_in_kernel;
+ int err = 0;
#endif
if (!handle)
/* Make our private copy of the filter */
- if (install_bpf_program(handle, filter) < 0) {
- snprintf(handle->errbuf, sizeof(handle->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ if (install_bpf_program(handle, filter) < 0)
+ /* install_bpf_program() filled in errbuf */
return -1;
- }
/*
* Run user level packet filter by default. Will be overriden if
}
if (can_filter_in_kernel) {
- if (set_kernel_filter(handle, &fcode) == 0)
+ if ((err = set_kernel_filter(handle, &fcode)) == 0)
{
/* Installation succeded - using kernel filter. */
handle->md.use_bpf = 1;
}
- else
+ else if (err == -1) /* Non-fatal error */
{
/*
* Print a warning if we weren't able to install
*/
if (fcode.filter != NULL)
free(fcode.filter);
+
+ if (err == -2)
+ /* Fatal error */
+ return -1;
#endif /* SO_ATTACH_FILTER */
return 0;
{
#ifdef HAVE_PF_PACKET_SOCKETS
int sock_fd = -1, device_id, arptype;
+ int err;
+ int fatal_err = 0;
struct packet_mreq mr;
/* One shot loop used for error handling - bail out with break */
handle->md.cooked = 0;
arptype = iface_get_arptype(sock_fd, device, ebuf);
- if (arptype == -1)
+ if (arptype == -1) {
+ fatal_err = 1;
break;
+ }
map_arphrd_to_dlt(handle, arptype, 1);
if (handle->linktype == -1 ||
handle->linktype == DLT_LINUX_SLL ||
if (device_id == -1)
break;
- if (iface_bind(sock_fd, device_id, ebuf) == -1)
+ if ((err = iface_bind(sock_fd, device_id, ebuf)) < 0) {
+ if (err == -2)
+ fatal_err = 1;
break;
+ }
} else {
/*
* This is cooked mode.
if (sock_fd != -1)
close(sock_fd);
- return 0;
+
+ if (fatal_err)
+ return -2;
+ else
+ return 0;
#else
strncpy(ebuf,
"New packet capturing interface not supported by build "
iface_bind(int fd, int ifindex, char *ebuf)
{
struct sockaddr_ll sll;
+ int err;
+ socklen_t errlen = sizeof(err);
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
return -1;
}
+ /* Any pending errors, e.g., network is down? */
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "getsockopt: %s", pcap_strerror(errno));
+ return -2;
+ }
+
+ if (err > 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "bind: %s", pcap_strerror(err));
+ return -2;
+ }
+
return 0;
}
}
}
}
+
if (handle->md.device != NULL)
free(handle->md.device);
+ handle->md.device = NULL;
}
/*
PCAP_ERRBUF_SIZE);
break;
}
+ did_atexit = 1;
}
ifr.ifr_flags |= IFF_PROMISC;
} while (0);
+ if (handle->md.clear_promisc)
+ pcap_close_linux(handle);
if (sock_fd != -1)
close(sock_fd);
return 0;
iface_bind_old(int fd, const char *device, char *ebuf)
{
struct sockaddr saddr;
+ int err;
+ socklen_t errlen = sizeof(err);
memset(&saddr, 0, sizeof(saddr));
strncpy(saddr.sa_data, device, sizeof(saddr.sa_data));
return -1;
}
+ /* Any pending errors, e.g., network is down? */
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "getsockopt: %s", pcap_strerror(errno));
+ return -1;
+ }
+
+ if (err > 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "bind: %s", pcap_strerror(err));
+ return -1;
+ }
+
return 0;
}
/*
* Save the socket's current mode, and put it in
* non-blocking mode; we drain it by reading packets
- * until we get an error (which we assume is a
+ * until we get an error (which is normally a
* "nothing more to be read" error).
*/
save_mode = fcntl(handle->fd, F_GETFL, 0);
while (recv(handle->fd, &drain, sizeof drain,
MSG_TRUNC) >= 0)
;
+ save_errno = errno;
fcntl(handle->fd, F_SETFL, save_mode);
+ if (save_errno != EAGAIN) {
+ /* Fatal error */
+ reset_kernel_filter(handle);
+ snprintf(handle->errbuf, sizeof(handle->errbuf),
+ "recv: %s", pcap_strerror(save_errno));
+ return -2;
+ }
}
}