Exemple #1
0
/**
 * returns number of bytes sent on success or -1 on error
 * Note: it is theoretically possible to get a return code >0 and < len
 * which for most people would be considered an error (the packet wasn't fully sent)
 * so you may want to test for recode != len too.
 *
 * Most socket API's have two interesting errors: ENOBUFS & EAGAIN.  ENOBUFS
 * is usually due to the kernel buffers being full.  EAGAIN happens when you
 * try to send traffic faster then the PHY allows.
 */
int
sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr *pkthdr)
{
    int retcode = 0, val;
    static u_char buffer[10000]; /* 10K bytes, enough for jumbo frames + pkthdr
                                  * larger than page size so made static to
                                  * prevent page misses on stack
                                  */
    static const size_t buffer_payload_size = sizeof(buffer) + sizeof(struct pcap_pkthdr);

    assert(sp);
    assert(data);

    if (len <= 0)
        return -1;

TRY_SEND_AGAIN:
    sp->attempt ++;

    switch (sp->handle_type) {
        case SP_TYPE_KHIAL:

            memcpy(buffer, pkthdr, sizeof(struct pcap_pkthdr));
            memcpy(buffer + sizeof(struct pcap_pkthdr), data, min(len, buffer_payload_size));

            /* tell the kernel module which direction the traffic is going */
            if (sp->cache_dir == TCPR_DIR_C2S) {  /* aka PRIMARY */
                val = KHIAL_DIRECTION_RX;
                if (ioctl(sp->handle.fd, KHIAL_SET_DIRECTION, (void *)&val) < 0) {
                    sendpacket_seterr(sp, "Error setting direction on %s: %s (%d)",
                            sp->device, strerror(errno), errno);
                    return -1;
                }
            } else if (sp->cache_dir == TCPR_DIR_S2C) {
                val = KHIAL_DIRECTION_TX;
                if (ioctl(sp->handle.fd, KHIAL_SET_DIRECTION, (void *)&val) < 0) {
                    sendpacket_seterr(sp, "Error setting direction on %s: %s (%d)",
                            sp->device, strerror(errno), errno);
                    return -1;
                }
            }

            /* write the pkthdr + packet data all at once */
            retcode = write(sp->handle.fd, (void *)buffer, sizeof(struct pcap_pkthdr) + len);
            retcode -= sizeof(struct pcap_pkthdr); /* only record packet bytes we sent, not pcap data too */
                    
            if (retcode < 0 && !sp->abort) {
                switch(errno) {
                    case EAGAIN:
                        sp->retry_eagain ++;
                        goto TRY_SEND_AGAIN;
                        break;
                    case ENOBUFS:
                        sp->retry_enobufs ++;
                        goto TRY_SEND_AGAIN;
                        break;
                    default:
                        sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)",
                                "khial", sp->sent + sp->failed + 1, strerror(errno), errno);
                }
                break;
            }

            break;

        case SP_TYPE_TUNTAP:
            retcode = write(sp->handle.fd, (void *)data, len);
            break;

            /* Linux PF_PACKET and TX_RING */
        case SP_TYPE_PF_PACKET:
        case SP_TYPE_TX_RING:
#if defined HAVE_PF_PACKET
#ifdef HAVE_TX_RING
            retcode = (int)txring_put(sp->tx_ring, data, len);
#else
            retcode = (int)send(sp->handle.fd, (void *)data, len, 0);
#endif

            /* out of buffers, or hit max PHY speed, silently retry
             * as long as we're not told to abort
             */
            if (retcode < 0 && !sp->abort) {
                switch (errno) {
                    case EAGAIN:
                        sp->retry_eagain ++;
                        goto TRY_SEND_AGAIN;
                        break;
                    case ENOBUFS:
                        sp->retry_enobufs ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    default:
                        sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
                                INJECT_METHOD, sp->sent + sp->failed + 1, strerror(errno), errno);
                }
            }

#endif /* HAVE_PF_PACKET */

            break;


        /* BPF */
        case SP_TYPE_BPF:
#if defined HAVE_BPF
            retcode = write(sp->handle.fd, (void *)data, len);

            /* out of buffers, or hit max PHY speed, silently retry */
            if (retcode < 0 && !sp->abort) {
                switch (errno) {
                    case EAGAIN:
                        sp->retry_eagain ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    case ENOBUFS:
                        sp->retry_enobufs ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    default:
                        sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
                                INJECT_METHOD, sp->sent + sp->failed + 1, strerror(errno), errno);
                }
            }
#endif
            break;

        /* Libdnet */
        case SP_TYPE_LIBDNET:

#if defined HAVE_LIBDNET
            retcode = eth_send(sp->handle.ldnet, (void*)data, (size_t)len);

            /* out of buffers, or hit max PHY speed, silently retry */
            if (retcode < 0 && !sp->abort) {
                switch (errno) {
                    case EAGAIN:
                        sp->retry_eagain ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    case ENOBUFS:
                        sp->retry_enobufs ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    default:
                        sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
                                INJECT_METHOD, sp->sent + sp->failed + 1, strerror(errno), errno);
                }
            }
#endif
            break;

        case SP_TYPE_LIBPCAP:
#if (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
#if defined HAVE_PCAP_INJECT
            /* 
             * pcap methods don't seem to support ENOBUFS, so we just straight fail
             * is there a better way???
             */
            retcode = pcap_inject(sp->handle.pcap, (void*)data, len);
#elif defined HAVE_PCAP_SENDPACKET
            retcode = pcap_sendpacket(sp->handle.pcap, data, (int)len);
#endif

            /* out of buffers, or hit max PHY speed, silently retry */
            if (retcode < 0 && !sp->abort) {
                switch (errno) {
                    case EAGAIN:
                        sp->retry_eagain ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    case ENOBUFS:
                        sp->retry_enobufs ++;
                        goto TRY_SEND_AGAIN;
                        break;

                    default:
                        sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
                                INJECT_METHOD, sp->sent + sp->failed + 1, pcap_geterr(sp->handle.pcap), errno);
                }
            }
#if defined HAVE_PCAP_SENDPACKET
            /* 
             * pcap_sendpacket returns 0 on success, not the packet length! 
             * hence, we have to fix retcode to be more standard on success
             */
            if (retcode == 0)
                retcode = len;
#endif /* HAVE_PCAP_SENDPACKET */

#endif /* HAVE_PCAP_INJECT || HAVE_PCAP_SENDPACKET */

            break;

        case SP_TYPE_QUICK_TX:
#ifdef HAVE_QUICK_TX
            retcode = quick_tx_send_packet(sp->qtx_dev, data, len);
            if (retcode < 0)
                sendpacket_seterr(sp, "Quick TX send failure");
#endif
            break;

        case SP_TYPE_NETMAP:
#ifdef HAVE_NETMAP
            retcode = sendpacket_send_netmap(sp, data, len);

            if (retcode == -1) {
                sendpacket_seterr(sp, "interface hung!!");
            } else if (retcode == -2) {
                /* this indicates that a retry was requested - this is not a failure */
                retcode = 0;
                goto TRY_SEND_AGAIN;
            }
#endif /* HAVE_NETMAP */
            break;

        default:
            errx(-1, "Unsupported sp->handle_type = %d", sp->handle_type);
    } /* end case */

    if (retcode < 0) {
        sp->failed ++;
    } else if (retcode != (int)len) {
        sendpacket_seterr(sp, "Only able to write %d bytes out of %u bytes total",
                retcode, len);
        sp->trunc_packets ++;
    } else {
        sp->bytes_sent += len;
        sp->sent ++;
    }
    return retcode;
}
Exemple #2
0
int main (int argc, char* argv[]) 
{
    int i;
    void* buffer;
    long length;
    int loops;
    __u64 packets_sent = 0;
    __u64 packet_bytes = 0;
    struct timeval tv_start;
    struct pcap_pkthdr* pcap_hdr;
    struct quick_tx qtx;

    if (argc != 3 && argc != 4) {
        printf("Usage: ./pcapsend <path-to-pcap> <interface> [loops]\n");
        exit(-1);
    }

    if (!read_pcap_file(argv[1], &buffer, &length)) {
        perror("Failed to read file! ");
        exit(-1);
    }

    if (argc == 4) {
        loops = atoi(argv[3]);
    } else {
        loops = 1;
    }

    memset(&qtx, 0, sizeof(qtx));
    int ret = quick_tx_open(argv[2], &qtx);

    if (ret == 0) {
        int blocks = quick_tx_alloc_mem_space(&qtx, length * loops);
        if (blocks >= 0) {
            printf("quick_tx mapped %d blocks of memory\n", blocks);
        } else {
            printf("quick_tx_alloc_mem_space failure\n");
            exit(-1);
        }
    } else {
        exit(-1);
    }

    gettimeofday(&tv_start,NULL);

    for (i = 0; i < loops; i++) {
        void* offset = buffer + sizeof(struct pcap_file_header);

        while(offset < buffer + length) {
            pcap_hdr = (struct pcap_pkthdr*) offset;
            offset += sizeof(struct pcap_pkthdr);

            if ((quick_tx_send_packet(&qtx, (const void*)offset, pcap_hdr->caplen)) < 0) {
                printf("An error occurred while trying to send a packet\n");
                goto quick_tx_error;
            }

            offset += pcap_hdr->caplen;
            packets_sent++;
            packet_bytes+= pcap_hdr->caplen;
        }
    }

    printf("Done, closing everything!\n");
    printf("\n");

quick_tx_error:
    quick_tx_close(&qtx);

    free(buffer);
    return 0;
}