/*
 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
 * YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with 
 * or without modification, are permitted provided that the following 
 * conditions and disclaimer are agreed and accepted by the user:
 * 
 * 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. Neither the names of the copyrighters, the name of the project which 
 * is related to this software (hereinafter referred to as "project") nor 
 * the names of the contributors may be used to endorse or promote products 
 * derived from this software without specific prior written permission.
 * 
 * 4. No merchantable use may be permitted without prior written 
 * notification to the copyrighters. However, using this software for the 
 * purpose of testing or evaluating any products including merchantable 
 * products may be permitted without any notification to the copyrighters.
 * 
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING 
 * BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE 
 * COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS 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.
 *
 * $TAHI: v6eval/lib/pkt/BpfAgent.cc,v 1.24 2002/05/27 09:56:21 akisada Exp $
 */
#include "BpfAgent.h"
#include "RunEnv.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <stdlib.h>
#include <string.h>

BpfAgent::BpfAgent(CSTR n,int32_t rbsize):filter_(n),buffer_(0),runStat_(eStop_) {
	if(fileDesc()<0) return;
	const Bpfilter& f=filter();
	if(f.promiscuous()<0||f.immediate(1)<0) {
		return;}

	if(RunEnv::filter()){ /* xxx: check TN def entry */
		struct bpf_program v6filter;
		struct bpf_insn insns[] = {
			BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x86dd, 0, 1),
			BPF_STMT(BPF_RET+BPF_K, (u_int)-1),  // accept
			BPF_STMT(BPF_RET+BPF_K, 0),          // ignore
		};
		v6filter.bf_len = 4;
		v6filter.bf_insns = insns;
		if(f.setfilter(&v6filter)<0) return;}
	uint32_t l=f.bufferSize();
	buffer_=(caddr_t)malloc(l+1);
	rbuf = new Ringbuf(2048,rbsize); /* xxx Ethernet Depend */
	readAction((agentFunc)&BpfAgent::receive);}

int BpfAgent::receive(int) {
	int rc=filter().receive(buffer_);
	for(int i=0;i < rc; ){
		char *next = buffer_+i;
		struct bpf_hdr *hdr = (struct bpf_hdr *)next;
		int datasize = hdr->bh_caplen + hdr->bh_hdrlen;
		if(!fifo.IsEmpty() &&
		   fifo.firstdatalen()==(int)hdr->bh_caplen &&
		   memcmp(fifo.firstdata(),next+hdr->bh_hdrlen,hdr->bh_caplen)==0){
			fifo.del();}
		else if(runStat() == eRun_)
			rbuf->write(next,datasize);
		if(datasize > rc)
			abort();
		i += BPF_WORDALIGN(datasize);}
	if (!rbuf->isEmpty()){
		struct bpf_hdr *hdr = (struct bpf_hdr *)buffer_;
		int datasize = hdr->bh_caplen + hdr->bh_hdrlen;
		readydata(buffer_,datasize);}
	return 0;}

int BpfAgent::readydata(char *,int32_t) {return 0;}

int BpfAgent::read(caddr_t buf, uint32_t len){
	int rc;
	if(len < rbuf->size()|| rbuf->isEmpty())
	  return 0;
	char *rb=rbuf->read(buf);
	if(rb==NULL)
	  return 0;
	struct bpf_hdr *hdr = (struct bpf_hdr *)rb;
	rc=hdr->bh_caplen + hdr->bh_hdrlen;
	return rc;}

int BpfAgent::readn(caddr_t buf, uint32_t n){
	int rc;
	if(rbuf->readn(n,buf)==0) rc=0;  
	else {
		struct bpf_hdr *hdr = (struct bpf_hdr *)buf;
		rc=hdr->bh_caplen + hdr->bh_hdrlen;}
	return rc;}

timeval* BpfAgent::ReceiveTimeOfOldestData() const{
	if(rbuf->isEmpty())
		return 0;
	return (timeval*)rbuf->readn(0,0);}

int BpfAgent::write(caddr_t p, uint32_t l) {
	fifo.add(p,l);
	return filter().send(p,l);}

bufStat BpfAgent::stat() const{
	struct bufStat rc;
	rc.datanum(rbuf->datanum());
	rc.size(rbuf->size());
	uint32_t recv,drop;
	filter().statistics(recv,drop);
	rc.recv(recv);
	rc.drop(drop);
	return rc;}

void BpfAgent::clear() {
#if 1
	/*
	  In rare case, clear() function is called before filterd out
	  all sent packets. So need to wait all sent packets filtered
	  out.

	  XXX : This routine is not enough tested.
	  */
	while(!fifo.IsEmpty())
		receive(0);
#endif
	rbuf->clear();
	filter_.flush();}


syntax highlighted by Code2HTML, v. 0.9.1