/*
 * loop.c -- the main loop of the capture engine
 * Part of the tcpick project
 *
 * Author: Francesco Stablum <duskdruid @ despammed.com>
 *
 * Copyright (C) 2003, 2004  Francesco Stablum
 * Licensed under the GPL
 *
 */

/* 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at you option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111,
 * USA.
 */

#include "tcpick.h"
#include "extern.h"

int 
got_packet (u_char * useless,
	    const struct pcap_pkthdr* hdr,
	    const u_char* packet) 
/* called by pcap_loop.
   this is the main loop for the packet engine. */

{ /* FIXME: this function is too long */

	/* check if the flag for checking for expired connections 
	   is turned on */
	
	if(expired_flag == CHECK_GOTPACKET) {
		check_expired();
	}
	expired_flag = CHECK_NOT;

	if(! packet)
		fault( "got_packet", "didn't grab packet" );

	count_packets++;
        
	ippacket=(struct ip *)(packet + datalink_size);

#if __BYTE_ORDER == __LITTLE_ENDIAN
	iplen = (ippacket->ip_len % 256) * 256 + (ippacket->ip_len) / 256;
#elif __BYTE_ORDER == __BIG_ENDIAN
	iplen = ippacket->ip_len;
#else
# error "Please fix <bits/endian.h>"
#endif

	switch(ippacket->ip_p) {
	case IPPROTO_TCP:

		tcppacket = (struct tcphdr *)(packet + datalink_size + IP_SIZE);
		tcp_size = tcppacket->doff * 4;
		payload = (u_char *)(packet + datalink_size + IP_SIZE + tcp_size);
		payload_len = iplen - IP_SIZE - tcp_size;

#ifdef TCPICK_DEBUG
		if( payload_len != (hdr->len - (int)( payload - packet ) ) ) {
		    suicide( "got_packet", 
			     "payload lenght calculated with iplen and hdr->len\n"
			     "differs by %d bytes\n"
			     "hdr->len = %d\n"
			     "datalink_size  = %d\n"
			     "IP_SIZE  = %d\n"
			     "iplen    = %d\n"
			     "tcp_size = %d\n"
			     "iplen - IP_SIZE - tcp_size = %d\n"
			     "(hdr->len - (int)( payload - packet ) = %d\n",
			     payload_len - (hdr->len - (int)( payload - packet )),
			     hdr->len,
			     datalink_size,
			     IP_SIZE,
			     iplen,
			     tcp_size,
			     payload_len,
			     (hdr->len - (int)( payload - packet ))
			    );
		}

#endif /* TCPICK_DEBUG */

		if( flags.header > 0 )
			display_header( stdout, ippacket, tcppacket, 
					payload_len );
		
		verify(); /* call the core to manage the packet */

		if( payload_len == 0 || SILENCE )
			goto end;

		out_flavour( flags.display_payload, 
			     stdout, payload, payload_len );
		
		break;

 	case IPPROTO_UDP:
 		udppacket = (struct udphdr *)(packet + datalink_size + IP_SIZE);
 		payload = (u_char *)(packet + datalink_size + IP_SIZE + sizeof(*udppacket)); 
 		payload_len = hdr->len - (int)( payload - packet );
 
 		if( payload_len == 0 || SILENCE )
			goto end;
 
 		out_flavour( flags.display_payload, 
 			     stdout, payload, payload_len );
 
 		break;
  				
		
	default: /* Packet with an unidentified protocol */
		debug( "Packet with unidentified protocol caught: %s > %s",
		       inet_ntoa(ippacket->ip_src),
		       inet_ntoa(ippacket->ip_dst) );
	}

end:
	
	if( flags.exitpackets != 0 ) {
		if (count_packets == flags.exitpackets)
			exit(EXIT_SUCCESS);
	}

	/* Now the callback is able to check! */
	expired_flag = CHECK_LISTENING;
}


syntax highlighted by Code2HTML, v. 0.9.1