hey guys,

i've modified a bit of the pcap code, just regarding the pcap_read_packet
function callback and a few of the wrappers for it. I'm getting a bunch of
errors when I add the code from the attached txt file to it, it gives errors
about pointers eg

ar.c:395: dereferencing pointer to incomplete type

now this happens on lines of code that have pcap_t as you can see I haven't
modified pcap_t at all so i'm a little confused why i'm getting this error.
any asisstance would be greatly appreciated.

Regards,
Iain McAleer
typedef int (*ais_pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);

int ais_pcap_loop(pcap_t *p, int cnt, ais_pcap_handler callback, u_char *user);
int ais_pcap_read(pcap_t *handle, int max_packets, ais_pcap_handler callback, u_char 
*user);
static int ais_pcap_read_packet(pcap_t *handle, ais_pcap_handler callback, u_char 
*userdata);


int ais_pcap_loop(pcap_t *p, int cnt, ais_pcap_handler callback, u_char *user) {
        register int n;

        for (;;) {
                if (p->sf.rfile != NULL)
                        n = pcap_offline_read(p, cnt, callback, user);
                else {
                        /*
                         * XXX keep reading until we get something
                         * (or an error occurs)
                         */
                        do {
                                n = ais_pcap_read(p, cnt, callback, user);
                        } while (n == 0);
                }
                if (n < 0)
                        return (n);
                if (n > 0)
                        return (n);
                if (cnt > 0) {
                        cnt -= n;
                        if (cnt <= 0)
                                return (0);
                }
        }
}

int ais_pcap_read(pcap_t *handle, int max_packets, ais_pcap_handler callback, u_char 
*user)
{
        /*
         * Currently, on Linux only one packet is delivered per read,
         * so we don't loop.
         */
        return ais_pcap_read_packet(handle, callback, user);
}

static int ais_pcap_read_packet(pcap_t *handle, ais_pcap_handler callback, u_char 
*userdata)
{
        int                     offset;
#ifdef HAVE_PF_PACKET_SOCKETS
        struct sockaddr_ll      from;
        struct sll_header       *hdrp;
#else
        struct sockaddr         from;
#endif
        socklen_t               fromlen;
        int                     packet_len, caplen;
        struct pcap_pkthdr      pcap_header;

#ifdef HAVE_PF_PACKET_SOCKETS
        /*
         * If this is a cooked device, leave extra room for a
         * fake packet header.
         */
        if (handle->md.cooked)
                offset = SLL_HDR_LEN;
        else
                offset = 0;
#else
        /*
         * This system doesn't have PF_PACKET sockets, so it doesn't
         * support cooked devices.
         */
        offset = 0;
#endif

        /* Receive a single packet from the kernel */

        do {
                fromlen = sizeof(from);
                packet_len = recvfrom( 
                        handle->fd, handle->buffer + offset + handle->offset,
                        handle->md.readlen - offset, MSG_TRUNC, 
                        (struct sockaddr *) &from, &fromlen);
        } while (packet_len == -1 && errno == EINTR);

        /* Check if an error occured */

        if (packet_len == -1) {
                if (errno == EAGAIN)
                        return 0;       /* no packet there */
                else {
                        snprintf(handle->errbuf, sizeof(handle->errbuf),
                                 "recvfrom: %s", pcap_strerror(errno));
                        return -1;
                }
        }

#ifdef HAVE_PF_PACKET_SOCKETS
        /*
         * If this is from the loopback device, reject outgoing packets;
         * we'll see the packet as an incoming packet as well, and
         * we don't want to see it twice.
         *
         * We can only do this if we're using PF_PACKET; the address
         * returned for SOCK_PACKET is a "sockaddr_pkt" which lacks
         * the relevant packet type information.
         */
        if (!handle->md.sock_packet &&
            from.sll_ifindex == handle->md.lo_ifindex &&
            from.sll_pkttype == PACKET_OUTGOING)
                return 0;
#endif

#ifdef HAVE_PF_PACKET_SOCKETS
        /*
         * If this is a cooked device, fill in the fake packet header.
         */
        if (handle->md.cooked) {
                /*
                 * Add the length of the fake header to the length
                 * of packet data we read.
                 */
                packet_len += SLL_HDR_LEN;

                hdrp = (struct sll_header *)handle->buffer;

                /*
                 * Map the PACKET_ value to a LINUX_SLL_ value; we
                 * want the same numerical value to be used in
                 * the link-layer header even if the numerical values
                 * for the PACKET_ #defines change, so that programs
                 * that look at the packet type field will always be
                 * able to handle DLT_LINUX_SLL captures.
                 */
                switch (from.sll_pkttype) {

                case PACKET_HOST:
                        hdrp->sll_pkttype = htons(LINUX_SLL_HOST);
                        break;

                case PACKET_BROADCAST:
                        hdrp->sll_pkttype = htons(LINUX_SLL_BROADCAST);
                        break;

                case PACKET_MULTICAST:
                        hdrp->sll_pkttype = htons(LINUX_SLL_MULTICAST);
                        break;

                case PACKET_OTHERHOST:
                        hdrp->sll_pkttype = htons(LINUX_SLL_OTHERHOST);
                        break;

                case PACKET_OUTGOING:
                        hdrp->sll_pkttype = htons(LINUX_SLL_OUTGOING);
                        break;

                default:
                        hdrp->sll_pkttype = -1;
                        break;
                }

                hdrp->sll_hatype = htons(from.sll_hatype);
                hdrp->sll_halen = htons(from.sll_halen);
                memcpy(hdrp->sll_addr, from.sll_addr,
                    (from.sll_halen > SLL_ADDRLEN) ?
                      SLL_ADDRLEN :
                      from.sll_halen);
                hdrp->sll_protocol = from.sll_protocol;
        }
#endif

        /*
         * XXX: According to the kernel source we should get the real 
         * packet len if calling recvfrom with MSG_TRUNC set. It does 
         * not seem to work here :(, but it is supported by this code
         * anyway. 
         * To be honest the code RELIES on that feature so this is really
         * broken with 2.2.x kernels.
         * I spend a day to figure out what's going on and I found out
         * that the following is happening: 
         *
         * The packet comes from a random interface and the packet_rcv 
         * hook is called with a clone of the packet. That code inserts
         * the packet into the receive queue of the packet socket.
         * If a filter is attached to that socket that filter is run
         * first - and there lies the problem. The default filter always
         * cuts the packet at the snaplen:
         *
         * # tcpdump -d
         * (000) ret      #68
         *
         * So the packet filter cuts down the packet. The recvfrom call 
         * says "hey, it's only 68 bytes, it fits into the buffer" with
         * the result that we don't get the real packet length. This 
         * is valid at least until kernel 2.2.17pre6. 
         *
         * We currently handle this by making a copy of the filter
         * program, fixing all "ret" instructions with non-zero
         * operands to have an operand of 65535 so that the filter
         * doesn't truncate the packet, and supplying that modified
         * filter to the kernel.
         */

        caplen = packet_len;
        if (caplen > handle->snapshot)
                caplen = handle->snapshot;

        /* Run the packet filter if not using kernel filter */
        if (!handle->md.use_bpf && handle->fcode.bf_insns) {
                if (bpf_filter(handle->fcode.bf_insns, handle->buffer, 
                                packet_len, caplen) == 0)
                {
                        /* rejected by filter */
                        return 0;
                }
        }

        /* Fill in our own header data */

        if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {
                snprintf(handle->errbuf, sizeof(handle->errbuf),
                         "ioctl: %s", pcap_strerror(errno));
                return -1;
        }
        pcap_header.caplen      = caplen;
        pcap_header.len         = packet_len;

        /* Call the user supplied callback function */
        handle->md.stat.ps_recv++;
        return callback(userdata, &pcap_header, handle->buffer + handle->offset);

        return 1;
}


Reply via email to