lwip-contrib-mac/ports/unix/netif/pcapif.c

219 lines
5.8 KiB
C
Raw Normal View History

2003-01-18 18:18:02 +00:00
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef linux /* Apparently, this doesn't work under Linux. */
#include "lwip/debug.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pcap.h>
#include "netif/etharp.h"
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "netif/unixif.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
2003-01-18 18:18:02 +00:00
#include "netif/tcpdump.h"
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
2003-01-18 18:18:02 +00:00
struct pcapif {
pcap_t *pd;
sys_sem_t sem;
u8_t pkt[2048];
u32_t len;
u32_t lasttime;
struct pbuf *p;
struct eth_addr *ethaddr;
};
static char errbuf[PCAP_ERRBUF_SIZE];
/*-----------------------------------------------------------------------------------*/
static err_t
pcapif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
static void
timeout(void *arg)
{
struct netif *netif;
struct pcapif *pcapif;
struct pbuf *p, *q;
u8_t *bufptr;
struct eth_hdr *ethhdr;
netif = (struct netif *)arg;
pcapif = netif->state;
ethhdr = (struct eth_hdr *)pcapif->pkt;
if (htons(ethhdr->type) != ETHTYPE_IP ||
2003-01-18 18:18:02 +00:00
ip_lookup(pcapif->pkt + 14, netif)) {
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_LINK, pcapif->len, PBUF_POOL);
if (p != NULL) {
2003-01-18 18:18:02 +00:00
/* We iterate over the pbuf chain until we have read the entire
packet into the pbuf. */
bufptr = (u_char *)pcapif->pkt;
for(q = p; q != NULL; q = q->next) {
/* Read enough bytes to fill this pbuf in the chain. The
available data in the pbuf is given by the q->len
variable. */
/* read data into(q->payload, q->len); */
bcopy(bufptr, q->payload, q->len);
bufptr += q->len;
}
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
tcpdump(p);
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
2003-01-18 18:18:02 +00:00
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
2003-01-18 18:18:02 +00:00
case ETHTYPE_IP:
etharp_ip_input(netif, p);
2003-01-18 18:18:02 +00:00
pbuf_header(p, -14);
netif->input(p, netif);
break;
case ETHTYPE_ARP:
etharp_arp_input(netif, pcapif->ethaddr, p);
break;
default:
pbuf_free(p);
break;
2003-01-18 18:18:02 +00:00
}
}
} else {
printf("ip_lookup dropped\n");
}
sys_sem_signal(pcapif->sem);
}
/*-----------------------------------------------------------------------------------*/
static void
callback(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *pkt)
{
struct netif *netif;
struct pcapif *pcapif;
u32_t time, lasttime;
netif = (struct netif *)arg;
pcapif = netif->state;
pcapif->len = hdr->len;
bcopy(pkt, pcapif->pkt, hdr->len);
time = hdr->ts.tv_sec * 1000 + hdr->ts.tv_usec / 1000;
lasttime = pcapif->lasttime;
pcapif->lasttime = time;
if (lasttime == 0) {
2003-01-18 18:18:02 +00:00
sys_timeout(1000, timeout, netif);
} else {
sys_timeout(time - lasttime, timeout, netif);
}
}
/*-----------------------------------------------------------------------------------*/
static void
pcapif_thread(void *arg)
{
struct netif *netif;
struct pcapif *pcapif;
netif = arg;
pcapif = netif->state;
while (1) {
2003-01-18 18:18:02 +00:00
pcap_loop(pcapif->pd, 1, callback, (u_char *)netif);
sys_sem_wait(pcapif->sem);
if (pcapif->p != NULL) {
2003-01-18 18:18:02 +00:00
netif->input(pcapif->p, netif);
}
}
}
/*-----------------------------------------------------------------------------------*/
err_t
2003-01-18 18:18:02 +00:00
pcapif_init(struct netif *netif)
{
struct pcapif *p;
p = malloc(sizeof(struct pcapif));
if (p == NULL)
return ERR_MEM;
2003-01-18 18:18:02 +00:00
netif->state = p;
netif->name[0] = 'p';
netif->name[1] = 'c';
netif->output = pcapif_output;
p->pd = pcap_open_offline("pcapdump", errbuf);
if (p->pd == NULL) {
2003-01-18 18:18:02 +00:00
printf("pcapif_init: failed %s\n", errbuf);
return ERR_IF;
2003-01-18 18:18:02 +00:00
}
p->sem = sys_sem_new(0);
p->p = NULL;
p->lasttime = 0;
sys_thread_new("pcapif_thread", pcapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
return ERR_OK;
2003-01-18 18:18:02 +00:00
}
/*-----------------------------------------------------------------------------------*/
#endif /* linux */