176404edcSAsim Jamshed /* for io_module_func def'ns */
276404edcSAsim Jamshed #include "io_module.h"
376404edcSAsim Jamshed /* for mtcp related def'ns */
476404edcSAsim Jamshed #include "mtcp.h"
576404edcSAsim Jamshed /* for errno */
676404edcSAsim Jamshed #include <errno.h>
776404edcSAsim Jamshed /* for logging */
876404edcSAsim Jamshed #include "debug.h"
976404edcSAsim Jamshed /* for num_devices_* */
1076404edcSAsim Jamshed #include "config.h"
1176404edcSAsim Jamshed 
1276404edcSAsim Jamshed #include <string.h>
1376404edcSAsim Jamshed #include <pcap.h>
1476404edcSAsim Jamshed 
1576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
1676404edcSAsim Jamshed struct pcap_private_context {
1776404edcSAsim Jamshed 	pcap_t *handle[MAX_DEVICES];
1876404edcSAsim Jamshed 	char   *dev_name[MAX_DEVICES];
1976404edcSAsim Jamshed 
2076404edcSAsim Jamshed 	struct pcap_pkthdr phdr;
2176404edcSAsim Jamshed 	const u_char *rdata;
2276404edcSAsim Jamshed 	u_char wdata[ETHERNET_FRAME_LEN];
2376404edcSAsim Jamshed 	uint16_t count[MAX_DEVICES];
2476404edcSAsim Jamshed } g_pcap_ctx;
25*02e590b6SAsim Jamshed 
26*02e590b6SAsim Jamshed #define PCAP_BUFFER_SIZE	(1048576 * 16U)
2776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
2876404edcSAsim Jamshed void
pcap_init_handle(struct mtcp_thread_context * ctxt)2976404edcSAsim Jamshed pcap_init_handle(struct mtcp_thread_context *ctxt)
3076404edcSAsim Jamshed {
3176404edcSAsim Jamshed 	ctxt->io_private_context = &g_pcap_ctx;
3276404edcSAsim Jamshed }
3376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
3476404edcSAsim Jamshed int32_t
pcap_recv_pkts(struct mtcp_thread_context * ctxt,int ifidx)3576404edcSAsim Jamshed pcap_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx)
3676404edcSAsim Jamshed {
3776404edcSAsim Jamshed 	if (ifidx < 0 || ifidx >= MAX_DEVICES)
3876404edcSAsim Jamshed 		return -1;
3976404edcSAsim Jamshed 
4076404edcSAsim Jamshed 	struct pcap_private_context *ppc = ctxt->io_private_context;
4176404edcSAsim Jamshed 	if ((ppc->rdata = pcap_next(ppc->handle[ifidx], &ppc->phdr)) == NULL)
4276404edcSAsim Jamshed 		return 0;
4376404edcSAsim Jamshed 
44*02e590b6SAsim Jamshed 	if (ppc->phdr.caplen != ppc->phdr.len)
45*02e590b6SAsim Jamshed 		TRACE_ERROR("caplen = %u, len: %u\n",
46*02e590b6SAsim Jamshed 			    ppc->phdr.caplen,
47*02e590b6SAsim Jamshed 			    ppc->phdr.len);
48*02e590b6SAsim Jamshed 
49*02e590b6SAsim Jamshed 	/* sanity check */
50*02e590b6SAsim Jamshed 	if (ppc->rdata == NULL)
51*02e590b6SAsim Jamshed 		return 0;
52*02e590b6SAsim Jamshed 
5376404edcSAsim Jamshed 	return 1; /* PCAP always receives only one packet */
5476404edcSAsim Jamshed }
5576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
5676404edcSAsim Jamshed uint8_t *
pcap_get_rptr(struct mtcp_thread_context * ctxt,int ifidx,int index,uint16_t * len)5776404edcSAsim Jamshed pcap_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len)
5876404edcSAsim Jamshed {
5976404edcSAsim Jamshed 	struct pcap_private_context *ppc = ctxt->io_private_context;
6076404edcSAsim Jamshed 	if (ppc->rdata == NULL)
6176404edcSAsim Jamshed 		return NULL;
6276404edcSAsim Jamshed 
6376404edcSAsim Jamshed 	*len = ppc->phdr.caplen;
6476404edcSAsim Jamshed 	return (uint8_t *)ppc->rdata;
6576404edcSAsim Jamshed }
6676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
6776404edcSAsim Jamshed int
pcap_send_pkts(struct mtcp_thread_context * ctxt,int nif)6876404edcSAsim Jamshed pcap_send_pkts(struct mtcp_thread_context *ctxt, int nif)
6976404edcSAsim Jamshed {
7076404edcSAsim Jamshed 	int ret = 0;
7176404edcSAsim Jamshed 	struct pcap_private_context *ppc = ctxt->io_private_context;
7276404edcSAsim Jamshed 
7376404edcSAsim Jamshed 	if (ppc->count[nif] > 0) {
7476404edcSAsim Jamshed 		ret = pcap_inject(ppc->handle[nif], ppc->wdata, ppc->phdr.len);
7576404edcSAsim Jamshed 	}
7676404edcSAsim Jamshed 
7776404edcSAsim Jamshed 	ppc->count[nif] = 0;
7876404edcSAsim Jamshed 	return (ret != -1) ? 1 : 0;
7976404edcSAsim Jamshed }
8076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
8176404edcSAsim Jamshed uint8_t *
pcap_get_wptr(struct mtcp_thread_context * ctxt,int ifidx,uint16_t pktsize)8276404edcSAsim Jamshed pcap_get_wptr(struct mtcp_thread_context *ctxt, int ifidx, uint16_t pktsize)
8376404edcSAsim Jamshed {
8476404edcSAsim Jamshed 	struct pcap_private_context *ppc = ctxt->io_private_context;
8576404edcSAsim Jamshed 	/* phdr can be reused */
8676404edcSAsim Jamshed 	ppc->phdr.caplen = ppc->phdr.len = pktsize;
8776404edcSAsim Jamshed 	ppc->count[ifidx] = 1;
8876404edcSAsim Jamshed 	return ppc->wdata;
8976404edcSAsim Jamshed }
9076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
9176404edcSAsim Jamshed int
pcap_get_nif(struct ifreq * ifr)9276404edcSAsim Jamshed pcap_get_nif(struct ifreq *ifr)
9376404edcSAsim Jamshed {
9476404edcSAsim Jamshed 	int i;
9576404edcSAsim Jamshed 
9676404edcSAsim Jamshed 	for (i = 0; i < g_config.mos->netdev_table->num; i++)
9776404edcSAsim Jamshed 		if (!strcmp(ifr->ifr_name, g_pcap_ctx.dev_name[i]))
9876404edcSAsim Jamshed 			return i;
9976404edcSAsim Jamshed 
10076404edcSAsim Jamshed 	return -1;
10176404edcSAsim Jamshed }
10276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
10376404edcSAsim Jamshed int32_t
pcap_select(struct mtcp_thread_context * ctxt)10476404edcSAsim Jamshed pcap_select(struct mtcp_thread_context *ctxt)
10576404edcSAsim Jamshed {
10676404edcSAsim Jamshed 	return 0;
10776404edcSAsim Jamshed }
10876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
10976404edcSAsim Jamshed void
pcap_destroy_handle(struct mtcp_thread_context * ctxt)11076404edcSAsim Jamshed pcap_destroy_handle(struct mtcp_thread_context *ctxt)
11176404edcSAsim Jamshed {
11276404edcSAsim Jamshed 	int i;
11376404edcSAsim Jamshed 	struct pcap_private_context *ppc = ctxt->io_private_context;
11476404edcSAsim Jamshed 	if (!ppc)
11576404edcSAsim Jamshed 		return;
11676404edcSAsim Jamshed 
11776404edcSAsim Jamshed 	for (i = 0; i < g_config.mos->netdev_table->num; i++) {
11876404edcSAsim Jamshed 		pcap_close(ppc->handle[i]);
11976404edcSAsim Jamshed 	}
12076404edcSAsim Jamshed 
12176404edcSAsim Jamshed 	ctxt->io_private_context = NULL;
12276404edcSAsim Jamshed }
12376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
12476404edcSAsim Jamshed void
pcap_load_module_upper_half(void)12576404edcSAsim Jamshed pcap_load_module_upper_half(void)
12676404edcSAsim Jamshed {
12776404edcSAsim Jamshed 	int i;
12876404edcSAsim Jamshed 	char errbuf[PCAP_ERRBUF_SIZE];
12976404edcSAsim Jamshed 	struct netdev_entry **ent = g_config.mos->netdev_table->ent;
13076404edcSAsim Jamshed 
13176404edcSAsim Jamshed 	for (i = 0; i < g_config.mos->netdev_table->num; i++) {
132*02e590b6SAsim Jamshed #if 0
13376404edcSAsim Jamshed 		g_pcap_ctx.handle[i] = pcap_open_live(ent[i]->dev_name, BUFSIZ, 1,
13476404edcSAsim Jamshed 										1, errbuf);
13576404edcSAsim Jamshed 		if (!g_pcap_ctx.handle[i]) {
13676404edcSAsim Jamshed 			TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name);
13776404edcSAsim Jamshed 			exit(EXIT_FAILURE);
13876404edcSAsim Jamshed 		}
139*02e590b6SAsim Jamshed #endif
140*02e590b6SAsim Jamshed 		g_pcap_ctx.handle[i] = pcap_create(ent[i]->dev_name, errbuf);
141*02e590b6SAsim Jamshed 		if (!g_pcap_ctx.handle[i]) {
142*02e590b6SAsim Jamshed 			TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name);
143*02e590b6SAsim Jamshed 			exit(EXIT_FAILURE);
144*02e590b6SAsim Jamshed 		}
14576404edcSAsim Jamshed 		g_pcap_ctx.dev_name[i] = ent[i]->dev_name;
146*02e590b6SAsim Jamshed 
147*02e590b6SAsim Jamshed 		if (pcap_set_buffer_size(g_pcap_ctx.handle[i], PCAP_BUFFER_SIZE) != 0) {
148*02e590b6SAsim Jamshed 			TRACE_ERROR("Can't increase buffer size to %u bytes\n",
149*02e590b6SAsim Jamshed 				    PCAP_BUFFER_SIZE);
150*02e590b6SAsim Jamshed 		}
151*02e590b6SAsim Jamshed 
152*02e590b6SAsim Jamshed 		if (pcap_activate(g_pcap_ctx.handle[i]) < 0) {
153*02e590b6SAsim Jamshed 			TRACE_ERROR("Failed to activate pcap handle!\n");
154*02e590b6SAsim Jamshed 			pcap_perror(g_pcap_ctx.handle[i], "");
155*02e590b6SAsim Jamshed 			exit(EXIT_FAILURE);
156*02e590b6SAsim Jamshed 		}
15776404edcSAsim Jamshed 	}
158522d5c66SAsim Jamshed 
159522d5c66SAsim Jamshed 	num_queues = 1;
16076404edcSAsim Jamshed }
16176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
16276404edcSAsim Jamshed io_module_func pcap_module_func = {
16376404edcSAsim Jamshed 	.load_module_upper_half	   = pcap_load_module_upper_half,
16476404edcSAsim Jamshed 	.load_module_lower_half	   = NULL,
16576404edcSAsim Jamshed 	.init_handle		   = pcap_init_handle,
16676404edcSAsim Jamshed 	.link_devices		   = NULL,
16776404edcSAsim Jamshed 	.release_pkt		   = NULL,
16876404edcSAsim Jamshed 	.send_pkts		   = pcap_send_pkts,
16976404edcSAsim Jamshed 	.get_wptr   		   = pcap_get_wptr,
17076404edcSAsim Jamshed 	.set_wptr   		   = NULL,
17176404edcSAsim Jamshed 	.recv_pkts		   = pcap_recv_pkts,
17276404edcSAsim Jamshed 	.get_rptr	   	   = pcap_get_rptr,
17376404edcSAsim Jamshed 	.select			   = NULL,
17476404edcSAsim Jamshed 	.destroy_handle		   = pcap_destroy_handle,
17576404edcSAsim Jamshed 	.dev_ioctl		   = NULL,
17676404edcSAsim Jamshed 	.get_nif		   = pcap_get_nif,
17776404edcSAsim Jamshed };
17876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
179