diff --git a/gtests/net/packetdrill/packet_socket_pcap.c b/gtests/net/packetdrill/packet_socket_pcap.c index 9b22101554412e398684f91247d5a348cbf26f29..04e31063260237fbc4c1d0eab63453ca742ec6b7 100644 --- a/gtests/net/packetdrill/packet_socket_pcap.c +++ b/gtests/net/packetdrill/packet_socket_pcap.c @@ -47,7 +47,9 @@ struct packet_socket { char *name; /* malloc-allocated copy of interface name */ - pcap_t *pcap; /* handle for sending, sniffing timestamped packets */ + pcap_t *pcap_in; /* handle for sniffing incoming packets */ + pcap_t *pcap_out; /* handle for sniffing outgoing packets */ + /* also used for sending packets */ char pcap_error[PCAP_ERRBUF_SIZE]; /* for libpcap errors */ int pcap_offset; /* offset of packet data in pcap buffer */ }; @@ -74,22 +76,49 @@ static void packet_socket_setup(struct packet_socket *psock) int data_link = -1, bpf_fd = -1, val = -1; DEBUGP("calling pcap_create() with %s\n", psock->name); - psock->pcap = pcap_create(psock->name, psock->pcap_error); - if (psock->pcap == NULL) - die_pcap_perror(psock->pcap, "pcap_create"); - - if (pcap_set_snaplen(psock->pcap, PACKET_READ_BYTES) != 0) - die_pcap_perror(psock->pcap, "pcap_set_snaplen"); - - if (pcap_activate(psock->pcap) != 0) - die_pcap_perror(psock->pcap, + psock->pcap_in = pcap_create(psock->name, psock->pcap_error); + if (psock->pcap_in == NULL) + die_pcap_perror(psock->pcap_in, "pcap_create"); + psock->pcap_out = pcap_create(psock->name, psock->pcap_error); + if (psock->pcap_out == NULL) + die_pcap_perror(psock->pcap_out, "pcap_create"); + + if (pcap_set_snaplen(psock->pcap_in, PACKET_READ_BYTES) != 0) + die_pcap_perror(psock->pcap_in, "pcap_set_snaplen"); + if (pcap_set_snaplen(psock->pcap_out, PACKET_READ_BYTES) != 0) + die_pcap_perror(psock->pcap_out, "pcap_set_snaplen"); + + if (pcap_activate(psock->pcap_in) != 0) + die_pcap_perror(psock->pcap_in, + "pcap_activate " + "(OpenBSD: another process (tcpdump?) " + "using bpf0?)"); + if (pcap_activate(psock->pcap_out) != 0) + die_pcap_perror(psock->pcap_out, "pcap_activate " "(OpenBSD: another process (tcpdump?) " "using bpf0?)"); - bpf_fd = pcap_get_selectable_fd(psock->pcap); + if (pcap_setdirection(psock->pcap_in, PCAP_D_IN) != 0) + die_pcap_perror(psock->pcap_in, "pcap_setdirection"); + if (pcap_setdirection(psock->pcap_out, PCAP_D_OUT) != 0) + die_pcap_perror(psock->pcap_out, "pcap_setdirection"); + + bpf_fd = pcap_get_selectable_fd(psock->pcap_in); + if (bpf_fd < 0) + die_pcap_perror(psock->pcap_in, "pcap_get_selectable_fd"); + + /* By default libpcap with BPF waits until a read buffer fills + * up before returning any packets. We use BIOCIMMEDIATE to + * force the BPF device to return the first packet + * immediately. + */ + val = 1; + if (ioctl(bpf_fd, BIOCIMMEDIATE, &val) < 0) + die_perror("ioctl BIOCIMMEDIATE on bpf fd"); + bpf_fd = pcap_get_selectable_fd(psock->pcap_out); if (bpf_fd < 0) - die_pcap_perror(psock->pcap, "pcap_get_selectable_fd"); + die_pcap_perror(psock->pcap_out, "pcap_get_selectable_fd"); /* By default libpcap with BPF waits until a read buffer fills * up before returning any packets. We use BIOCIMMEDIATE to @@ -101,7 +130,7 @@ static void packet_socket_setup(struct packet_socket *psock) die_perror("ioctl BIOCIMMEDIATE on bpf fd"); /* Find data link type. */ - data_link = pcap_datalink(psock->pcap); + data_link = pcap_datalink(psock->pcap_in); DEBUGP("data_link: %d\n", data_link); /* Based on the data_link type, calculate the offset of the @@ -150,12 +179,15 @@ void packet_socket_set_filter(struct packet_socket *psock, DEBUGP("setting BPF filter: %s\n", filter_str); - if (pcap_compile(psock->pcap, &bpf_code, filter_str, 1, 0) != 0) - die_pcap_perror(psock->pcap, "pcap_compile"); - - if (pcap_setfilter(psock->pcap, &bpf_code) != 0) - die_pcap_perror(psock->pcap, "pcap_setfilter"); - + if (pcap_compile(psock->pcap_in, &bpf_code, filter_str, 1, 0) != 0) + die_pcap_perror(psock->pcap_in, "pcap_compile"); + if (pcap_setfilter(psock->pcap_in, &bpf_code) != 0) + die_pcap_perror(psock->pcap_in, "pcap_setfilter"); + pcap_freecode(&bpf_code); + if (pcap_compile(psock->pcap_out, &bpf_code, filter_str, 1, 0) != 0) + die_pcap_perror(psock->pcap_out, "pcap_compile"); + if (pcap_setfilter(psock->pcap_out, &bpf_code) != 0) + die_pcap_perror(psock->pcap_out, "pcap_setfilter"); pcap_freecode(&bpf_code); free(filter_str); } @@ -176,7 +208,8 @@ void packet_socket_free(struct packet_socket *psock) if (psock->name != NULL) free(psock->name); - pcap_close(psock->pcap); + pcap_close(psock->pcap_in); + pcap_close(psock->pcap_out); memset(psock, 0, sizeof(*psock)); /* paranoia to catch bugs*/ free(psock); @@ -207,8 +240,8 @@ int packet_socket_writev(struct packet_socket *psock, DEBUGP("calling pcap_inject with %d bytes\n", len); - if (pcap_inject(psock->pcap, buf, len) != len) - die_pcap_perror(psock->pcap, "pcap_inject"); + if (pcap_inject(psock->pcap_out, buf, len) != len) + die_pcap_perror(psock->pcap_out, "pcap_inject"); free(buf); return STATUS_OK; @@ -221,8 +254,15 @@ int packet_socket_receive(struct packet_socket *psock, int status = 0; struct pcap_pkthdr *pkt_header = NULL; const u8 *pkt_data = NULL; + pcap_t *pcap; + + DEBUGP("calling pcap_next_ex() for direction %s\n", + direction == DIRECTION_INBOUND ? "inbound" : "outbound"); - DEBUGP("calling pcap_next_ex()\n"); + if (direction == DIRECTION_INBOUND) + pcap = psock->pcap_in; + else + pcap = psock->pcap_out; /* Something about the way we're doing BIOCIMMEDIATE * causes libpcap to return 0 if there's no packet @@ -234,14 +274,13 @@ int packet_socket_receive(struct packet_socket *psock, * here. TODO(ncardwell): fix this. */ while (1) { - status = pcap_next_ex(psock->pcap, &pkt_header, - &pkt_data); + status = pcap_next_ex(pcap, &pkt_header, &pkt_data); if (status == 1) break; /* got a packet */ else if (status == 0) return STATUS_ERR; /* no packet yet */ else if (status == -1) - die_pcap_perror(psock->pcap, "pcap_next_ex"); + die_pcap_perror(pcap, "pcap_next_ex"); else if (status == -2) die("pcap_next_ex: EOF in save file?!\n"); else