Add pcap_io object which represent pcap io API to simplify and make
more transparent pcap access.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 pcap_io.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 pcap_io.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 333 insertions(+)
 create mode 100644 pcap_io.c

diff --git a/pcap_io.c b/pcap_io.c
new file mode 100644
index 0000000..b82792a
--- /dev/null
+++ b/pcap_io.c
@@ -0,0 +1,190 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "bpf.h"
+#include "pcap_io.h"
+#include "xmalloc.h"
+
+void pcap_io_init(struct pcap_io *io, enum pcap_ops_groups ops_type)
+{
+       io->ops = pcap_ops[ops_type];
+       io->ops_type = ops_type;
+       io->bpf_ops = NULL;
+       io->jumbo = false;
+       io->truncated = 0;
+       io->path = NULL;
+       io->fd = -1;
+       
+       bug_on(!io->ops);
+}
+
+void pcap_io_open(struct pcap_io *io, const char *path, enum pcap_mode mode)
+{
+       if (mode == PCAP_MODE_RD) {
+               if (!strncmp("-", path, strlen("-"))) {
+                       io->fd = dup_or_die(fileno(stdin));
+                       close(fileno(stdin));
+
+                       if (io->ops_type == PCAP_OPS_MM)
+                               pcap_io_init(io, PCAP_OPS_SG);
+               } else {
+                       io->fd = open(path, O_RDONLY | O_LARGEFILE | O_NOATIME);
+                       if (io->fd < 0 && errno == EPERM)
+                               io->fd = open_or_die(path, O_RDONLY | 
O_LARGEFILE);
+               }
+       } else if (mode == PCAP_MODE_WR) {
+               if (!strncmp("-", path, strlen("-"))) {
+                       io->fd = dup_or_die(fileno(stdout));
+                       close(fileno(stdout));
+
+                       if (io->ops_type == PCAP_OPS_MM)
+                               pcap_io_init(io, PCAP_OPS_SG);
+               } else {
+                       io->fd = open_or_die_m(path, O_RDWR | O_CREAT | O_TRUNC 
|
+                                              O_LARGEFILE, DEFFILEMODE);
+               }
+       } else {
+               bug();
+       }
+
+       if (io->fd < 0)
+               panic("pcap_io: Cannot open file %s! %s.\n", path, 
strerror(errno));
+
+       if (io->ops->init_once_pcap)
+               io->ops->init_once_pcap(io->enforce_prio);
+
+       io->path = path;
+       io->mode = mode;
+}
+
+static int pcap_io_prepare_access(struct pcap_io *io)
+{
+       int ret;
+
+       if (io->ops->prepare_access_pcap) {
+               ret = io->ops->prepare_access_pcap(io->fd, io->mode, io->jumbo);
+               if (ret) {
+                       fprintf(stderr, "pcap_io: Error prepare %s pcap!\n",
+                               io->mode == PCAP_MODE_RD ? "reading" : 
"writing");
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+void pcap_io_header_copy(struct pcap_io *to, struct pcap_io *from)
+{
+       to->link_type = from->link_type;
+       to->magic     = from->magic;
+}
+
+int pcap_io_header_read(struct pcap_io *io)
+{
+       int ret;
+
+       ret = io->ops->pull_fhdr_pcap(io->fd, &io->magic, &io->link_type);
+       if (ret) {
+               fprintf(stderr, "pcap_io: Error reading pcap header!\n");
+               return ret;
+       }
+
+       return pcap_io_prepare_access(io);
+}
+
+int pcap_io_header_write(struct pcap_io *io)
+{
+       int ret;
+
+       ret = io->ops->push_fhdr_pcap(io->fd, io->magic, io->link_type);
+       if (ret) {
+               fprintf(stderr, "pcap_io: Error writing pcap header!\n");
+               return ret;
+       }
+
+       return pcap_io_prepare_access(io);
+}
+
+int pcap_io_packet_read(struct pcap_io *io, struct pcap_packet *pkt)
+{
+       int ret;
+
+       do {
+               ret = io->ops->read_pcap(io->fd, &pkt->phdr, io->magic,
+                                        pkt->buf, pkt->buf_len);
+               if (unlikely(ret < 0)) {
+                       return 0;
+               }
+               if (unlikely(pcap_packet_len_get(pkt) == 0)) {
+                       pkt->io->truncated++;
+                       continue;
+               }
+               if (unlikely(pcap_packet_len_get(pkt) > pkt->buf_len)) {
+                       pcap_packet_len_set(pkt, pkt->buf_len);
+                       pkt->io->truncated++;
+               }
+       } while (io->bpf_ops &&
+                       !bpf_run_filter(io->bpf_ops, pkt->buf,
+                                        pcap_packet_len_get(pkt)));
+
+       return ret;
+}
+
+int pcap_io_packet_write(struct pcap_io *io, struct pcap_packet *pkt)
+{
+       size_t pcap_len = pcap_get_length(&pkt->phdr, io->magic);
+       uint32_t len = io->ops->write_pcap(io->fd, &pkt->phdr, io->magic,
+                                          pkt->buf, pcap_len);
+
+       if (unlikely(len != pcap_get_total_length(&pkt->phdr, io->magic)))
+               return -1;
+
+       return 0;
+}
+
+void pcap_io_close(struct pcap_io *io)
+{
+       if (io->fd >= 0) {
+               if (io->mode == PCAP_MODE_WR)
+                       io->ops->fsync_pcap(io->fd);
+
+               if (io->ops->prepare_close_pcap)
+                       io->ops->prepare_close_pcap(io->fd, io->mode);
+
+               if (!strncmp("-", io->path, strlen("-")))
+                       dup2(io->fd, fileno(stdin));
+
+       }
+}
+
+struct pcap_packet *pcap_packet_alloc(struct pcap_io *io)
+{
+       struct pcap_packet *pkt = xzmalloc(sizeof(*io));
+
+       pkt->io = io;
+       return pkt;
+}
+
+void pcap_packet_free(struct pcap_packet *pkt)
+{
+       if (pkt->is_buf_alloc)
+               xfree(pkt->buf);
+
+       xfree(pkt);
+}
+
+void pcap_packet_buf_alloc(struct pcap_packet *pkt, uint32_t len)
+{
+       pkt->buf = xmalloc_aligned(len, CO_CACHE_LINE_SIZE);
+       pkt->buf_len = len;
+
+       pkt->is_buf_alloc = true;
+}
diff --git a/pcap_io.h b/pcap_io.h
index 4e41362..0026361 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -17,6 +17,7 @@
 #include <linux/if.h>
 #include <linux/if_packet.h>
 #include <linux/if_arp.h>
+#include <linux/filter.h>
 
 #include "built_in.h"
 #include "die.h"
@@ -164,6 +165,31 @@ struct pcap_file_ops {
        void (*fsync_pcap)(int fd);
 };
 
+struct pcap_io {
+       uint32_t link_type;
+       uint32_t magic;
+
+       const struct pcap_file_ops *ops;
+       enum pcap_ops_groups ops_type;
+       enum pcap_type type;
+       enum pcap_mode mode;
+       const char *path;
+       bool enforce_prio;
+       bool jumbo;
+       int fd;
+
+       struct sock_fprog *bpf_ops;
+       uint64_t truncated;
+};
+
+struct pcap_packet {
+       pcap_pkthdr_t phdr;
+       struct pcap_io *io;
+       bool is_buf_alloc;
+       uint32_t buf_len;
+       uint8_t *buf;
+};
+
 extern const struct pcap_file_ops pcap_rw_ops __maybe_unused;
 extern const struct pcap_file_ops pcap_sg_ops __maybe_unused;
 extern const struct pcap_file_ops pcap_mm_ops __maybe_unused;
@@ -896,4 +922,121 @@ static int pcap_generic_push_fhdr(int fd, uint32_t magic, 
uint32_t linktype)
        return 0;
 }
 
+extern void pcap_io_init(struct pcap_io *io, enum pcap_ops_groups ops_type);
+extern void pcap_io_open(struct pcap_io *io, const char *path, enum pcap_mode 
mode);
+extern void pcap_io_header_copy(struct pcap_io *to, struct pcap_io *from);
+extern int pcap_io_header_read(struct pcap_io *io);
+extern int pcap_io_header_write(struct pcap_io *io);
+extern int pcap_io_packet_read(struct pcap_io *io, struct pcap_packet *pk);
+extern int pcap_io_packet_write(struct pcap_io *io, struct pcap_packet *pkt);
+extern void pcap_io_close(struct pcap_io *io);
+
+extern struct pcap_packet *pcap_packet_alloc(struct pcap_io *io);
+extern void pcap_packet_free(struct pcap_packet *pkt);
+extern void pcap_packet_buf_alloc(struct pcap_packet *pkt, uint32_t len);
+
+static inline uint32_t pcap_packet_len_get(struct pcap_packet *pkt)
+{
+       return pcap_get_length(&pkt->phdr, pkt->io->magic);
+}
+
+static inline void pcap_packet_len_set(struct pcap_packet *pkt, uint32_t len)
+{
+       pcap_set_length(&pkt->phdr, pkt->io->magic, len);
+}
+
+static inline uint32_t pcap_io_pcap_type_get(struct pcap_io *io)
+{
+       return io->magic;
+}
+
+static inline void pcap_io_pcap_type_set(struct pcap_io *io, uint32_t type)
+{
+       io->magic = type;
+}
+
+static inline uint32_t pcap_io_link_type_get(struct pcap_io *io)
+{
+       return io->link_type;
+}
+
+static inline void pcap_io_link_type_set(struct pcap_io *io, uint32_t 
link_type)
+{
+       io->link_type = link_type;
+}
+
+static inline void pcap_io_enforce_prio_set(struct pcap_io *io, bool enforce)
+{
+       io->enforce_prio = enforce;
+}
+
+static inline void pcap_io_jumbo_enable_set(struct pcap_io *io, bool jumbo)
+{
+       io->jumbo = jumbo;
+}
+
+static inline void pcap_io_bpf_apply(struct pcap_io *io, struct sock_fprog 
*bpf)
+{
+       io->bpf_ops = bpf;
+}
+
+static inline uint64_t pcap_io_truncated_get(struct pcap_io *io)
+{
+       return io->truncated;
+}
+
+static inline void pcap_packet_buf_set(struct pcap_packet *pkt, uint8_t *buf)
+{
+       pkt->buf = buf;
+}
+
+static inline uint8_t *pcap_packet_buf_get(struct pcap_packet *pkt)
+{
+       return pkt->buf;
+}
+
+static inline void pcap_packet_buf_len_set(struct pcap_packet *pkt, uint32_t 
len)
+{
+       pkt->buf_len = len;
+}
+
+static inline uint32_t pcap_packet_buf_len_get(struct pcap_packet *pkt)
+{
+       return pkt->buf_len;
+}
+
+static inline uint8_t *pcap_packet_payload_get(struct pcap_packet *pkt)
+{
+       return pkt->buf;
+}
+
+static inline pcap_pkthdr_t *pcap_packet_header_get(struct pcap_packet *pkt)
+{
+       return &pkt->phdr;
+}
+
+static inline void pcap_packet_to_tpacket2(struct pcap_packet *pkt,
+                                          struct tpacket2_hdr *thdr,
+                                          struct sockaddr_ll *sll)
+{
+       pcap_pkthdr_to_tpacket_hdr(&pkt->phdr, pkt->io->magic, thdr, sll);
+}
+
+static inline void pcap_packet_from_tpacket2(struct pcap_packet *pkt,
+                                            struct tpacket2_hdr *thdr,
+                                            struct sockaddr_ll *sll)
+{
+       tpacket_hdr_to_pcap_pkthdr(thdr, sll, &pkt->phdr, pkt->io->magic);
+}
+
+#ifdef HAVE_TPACKET3
+static inline void pcap_packet_from_tpacket3(struct pcap_packet *pkt,
+                                            struct tpacket3_hdr *thdr,
+                                            struct sockaddr_ll *sll)
+
+{
+       tpacket3_hdr_to_pcap_pkthdr(thdr, sll, &pkt->phdr, pkt->io->magic);
+}
+#endif
+
 #endif /* PCAP_IO_H */
-- 
2.10.2

-- 
You received this message because you are subscribed to the Google Groups 
"netsniff-ng" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to netsniff-ng+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to