X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/cfa5a9af6cc58e5e8fcebfbe037f8697b3d43dae..83b51abcee9dffe2a58c564fb390ce3a3e772f1a:/pcap-linux.c diff --git a/pcap-linux.c b/pcap-linux.c index a12e64dd..bef5c437 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -34,7 +34,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.129.2.18 2008-04-14 20:41:52 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.129.2.22 2008-08-06 07:40:20 guy Exp $ (LBL)"; #endif /* @@ -471,7 +471,7 @@ static void pcap_cleanup_linux( pcap_t *handle ) free(handle->md.device); handle->md.device = NULL; } - pcap_cleanup_live_common(p); + pcap_cleanup_live_common(handle); } /* @@ -625,10 +625,10 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) #else struct sockaddr from; #endif - socklen_t fromlen; int packet_len, caplen; struct pcap_pkthdr pcap_header; - + struct iovec iov; + struct msghdr msg; #ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, leave extra room for a @@ -646,9 +646,34 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) offset = 0; #endif - /* Receive a single packet from the kernel */ - + /* + * Receive a single packet from the kernel. + * We ignore EINTR, as that might just be due to a signal + * being delivered - if the signal should interrupt the + * loop, the signal handler should call pcap_breakloop() + * to set handle->break_loop (we ignore it on other + * platforms as well). + * We also ignore ENETDOWN, so that we can continue to + * capture traffic if the interface goes down and comes + * back up again; comments in the kernel indicate that + * we'll just block waiting for packets if we try to + * receive from a socket that delivered ENETDOWN, and, + * if we're using a memory-mapped buffer, we won't even + * get notified of "network down" events. + */ bp = handle->buffer + handle->offset; + + msg.msg_name = &from; + msg.msg_namelen = sizeof(from); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + iov.iov_len = handle->bufsize - offset; + iov.iov_base = bp + offset; + do { /* * Has "pcap_breakloop()" been called? @@ -662,12 +687,9 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) handle->break_loop = 0; return -2; } - fromlen = sizeof(from); - packet_len = recvfrom( - handle->fd, bp + offset, - handle->bufsize - offset, MSG_TRUNC, - (struct sockaddr *) &from, &fromlen); - } while (packet_len == -1 && errno == EINTR); + + packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC); + } while (packet_len == -1 && (errno == EINTR || errno == ENETDOWN)); /* Check if an error occured */ @@ -1539,6 +1561,17 @@ static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok) handle->linktype = DLT_LINUX_LAPD; break; +#ifndef ARPHRD_NONE +#define ARPHRD_NONE 0xFFFE +#endif + case ARPHRD_NONE: + /* + * No link-layer header; packets are just IP + * packets, so use DLT_RAW. + */ + handle->linktype = DLT_RAW; + break; + default: handle->linktype = -1; break; @@ -1711,10 +1744,10 @@ activate_new(pcap_t *handle) } if ((err = iface_bind(sock_fd, handle->md.ifindex, - handle->errbuf)) < 0) { + handle->errbuf)) != 1) { close(sock_fd); - if (err == -2) - return PCAP_ERROR; + if (err < 0) + return err; else return 0; /* try old mechanism */ } @@ -2172,6 +2205,8 @@ iface_get_id(int fd, const char *device, char *ebuf) /* * Bind the socket associated with FD to the given device. + * Return 1 on success, 0 if we should try a SOCK_PACKET socket, + * or a PCAP_ERROR_ value on a hard error. */ static int iface_bind(int fd, int ifindex, char *ebuf) @@ -2186,9 +2221,20 @@ iface_bind(int fd, int ifindex, char *ebuf) sll.sll_protocol = htons(ETH_P_ALL); if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, - "bind: %s", pcap_strerror(errno)); - return -1; + if (errno == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } else { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "bind: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } } /* Any pending errors, e.g., network is down? */ @@ -2196,16 +2242,25 @@ iface_bind(int fd, int ifindex, char *ebuf) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); - return -2; + return 0; } - if (err > 0) { + if (err == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } else if (err > 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(err)); - return -2; + return 0; } - return 0; + return 1; } /*