/*
 * Copyright (c) 2004-2005 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: packet.c 8180 2008-01-16 02:35:01Z jomi $
 */

#include <stdlib.h>
#include <string.h>
#include "packet.h"
#include "dagrandom.h"

packet_t * packetNew (unsigned char type, char * id) {
	packet_t * p;

	p = (packet_t *) malloc(sizeof(packet_t));
	p->type = type;

	p->id = strdup(id);
	strcpy (p->id, id);

	//printf("[packetNew] id: '%s', p->id: '%s'\n", id, p->id);

	switch (type) {
		case PKT_ETH802_3:
			p->p = (void *) packetNewEth802_3();
			break;
		case PKT_ETH_II:
			p->p = (void *) packetNewEth_II();
			break;
		case PKT_POS:
			p->p = (void *) packetNewPos();
			break;
		case PKT_ATM:
			p->p = (void *) packetNewAtm();
			break;
		case PKT_AAL5:
			p->p = (void *) packetNewAal5();
			break;
		case PKT_IB:
			p->p = (void *) packetNewIB();
			break;
		default:
			p->p = NULL;
			break;
	}

	return p;
}

packet_eth802_3_t * packetNewEth802_3 () {
	packet_eth802_3_t * p;

	p = (packet_eth802_3_t *) malloc(sizeof(packet_eth802_3_t));
	p->src_addr = macNew ();
	p->dst_addr = macNew ();
	p->fcs_size = 0;
	p->payload = NULL;

	return p;
}

packet_eth_II_t * packetNewEth_II () {
	packet_eth_II_t * p;

	p = (packet_eth_II_t *) malloc(sizeof(packet_eth_II_t));
	p->src_addr = macNew ();
	p->dst_addr = macNew ();
	p->fcs_size = 0;
	p->payload = NULL;
	p->protocol = 0x0000;

	return p;
}

packet_pos_t * packetNewPos () {
	packet_pos_t * p;

	p = (packet_pos_t *) malloc(sizeof(packet_pos_t));
	p->address = 0xff;	// all stations
	p->control = 0x03;	// unnumbered info
	p->protocol_size = 2;	// 2 bytes (16 bits) protocol field size
	p->protocol = 0;	// default protocol: unknown
	//p->payload = distrNew(_CONSTANT, 100, 0, 0, NULL);
	p->payload = NULL;
	p->fcs_size = 4;	// 4 bytes (32 bits) fcs field size

	return p;
}

packet_atm_t * packetNewAtm () {
	packet_atm_t * p;

	p = (packet_atm_t *) malloc(sizeof(packet_atm_t));
	p->type = ATM_TYPE_UNI;
	p->gfc = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->vpi = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->vci = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->pt  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->clp = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->payload = NULL;

	return p;
}

packet_aal5_t * packetNewAal5 () {
	packet_aal5_t * p;

	p = (packet_aal5_t *) malloc(sizeof(packet_aal5_t));
	p->type = ATM_TYPE_UNI;
	p->gfc = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->vpi = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->vci = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->pt  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->clp = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->payload = NULL;
	p->uu  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->cpi = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->crc = distrNew (_CONSTANT, 0, 0, 0, NULL);

	return p;
}


//
// Packet Free and subtypes
//

void packetFree (packet_t * p) {
	switch (p->type) {
		case PKT_ETH802_3:
			packetFreeEth((packet_eth_t *)p->p);
			break;

		case PKT_POS:
			packetFreePos((packet_pos_t *)p->p);
			break;

		default:
			break;
	}

	free(p->id);
	free(p);
}

void packetFreeEth (packet_eth_t * p) {
	free(p->src_addr);
	free(p->dst_addr);
	free(p);
}

void packetFreePos (packet_pos_t * p) {
	free(p);
}


//
// MAC Address stuff
//

mac_t * macNew () {
	mac_t * m;

	m = (mac_t *) malloc(sizeof(mac_t));
	m->type = MAC_STATIC;
	memset(m->mac, 0, 6);
	BITCLEAR(m->bitset);

	return m;
}

void macGet (mac_t * mac, unsigned char * array) {
	int i;
	unsigned int nibble;
	
	switch (mac->type) {
		case MAC_STATIC:
			memcpy (array, mac->mac, 6);
			break;
		case MAC_WILDCARD:
			memcpy (array, mac->mac, 6);
			for (i=1; i<=12; i++) {
				if(BITGET(mac->bitset,i+1)) {
					nibble = randomNibble();
					//printf ("[macGet] nibble: %d(%d)\n", nibble, i);
					if (i%2)
						array[i/2] |= nibble;
					else
						array[i/2] |= nibble << 4;
				}
			}
			break;
	}
}

//
// Payload stuff
//
payload_t * payloadNew (char type, void * contents, distribution_t * distr) {
	payload_t * aux;

	aux = (payload_t *) malloc (sizeof(payload_t));
	aux->type = type;
	aux->contents = contents;
	aux->distr = distr;

	return aux;
}

//
// Counters stuff
//
counter_t * counterNew (char *id, distribution_t * distr, unsigned char size) {
	counter_t * c;

	c = (counter_t *) malloc (sizeof(counter_t));
	c->id = id;
	c->distr = distr;
	c->size = size;

	return c;
}

packet_ib_t* packetNewIB()
{
	packet_ib_t* p;

	p = (packet_ib_t *) malloc(sizeof(packet_ib_t));
	p->type = IB_TYPE_LOCAL;
	p->lrh_vl = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->lrh_lver = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->lrh_slid = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->lrh_dlid  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->bth_opcode = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->bth_psn = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->bth_qp  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->bth_tver  = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->lrh_slevel = distrNew (_CONSTANT, 0, 0, 0, NULL);
	p->src_qp    =  distrNew (_CONSTANT, 0, 0, 0, NULL); 
	p->payload = NULL;
	return p;
}


