/*
 * Copyright (c) 2004 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: gram.y 12677 2010-03-30 22:09:45Z wilson.zhu $
 */

%{

/* ------------------------------------------------------------------
   Initial code (copied verbatim to the output file)
   ------------------------------------------------------------------ */

// Includes

#ifdef _WIN32 
#include <malloc.h>
#endif /* _WIN32 */
//#ifdef LINUX
//#include <malloc.h>  // _alloca is used by the parser
//#else
#include <stdlib.h>

#include <string.h>  // strcpy

#include "lex.h"	// the lexer
#include "list.h"	// list data type
#include "packet.h"	// packet data type
#include "cmd.h"	// command data type
#include "dagrandom.h"	// random numbers and statistic distributions
#include "daggen.h"	// daggen general options

// Some yacc (bison) defines
#define YYDEBUG 1	      // Generate debug code; needed for YYERROR_VERBOSE
#define YYERROR_VERBOSE // Give a more specific parse error message 

// Global variables
// Mainly are extern because we cannot initialise them here
// Check for declarations in daggen.c
extern list_t *list;			// symbol list
extern list_t *packet_list;		// packet list
extern list_t *group_list;		// traffic groups list
extern list_t *counter_list;		// counters list
extern packet_t *packet;		// the present packet
extern options_t daggen_options;	// general options
distribution_t * distr_aux;		// pointer for number distribution
char bypass = 0;			// bypass packet if already declared
list_t *payload_list;			// List of payload contents
payload_t * pload;

// Error-reporting function must be defined by the caller
void Error (char *format, ...);

// Forward references
void yyerror (char *msg);

// Own functions
//void checkPacket (char *symbol);
//void checkSend (char * symbol, unsigned long);
//int elemExists (char * str);
//void printMac (unsigned char * mac);
//unsigned char hexToChar (char c);
////void checkMac (char *mac_str, mac_t * old_mac);
//mac_t * checkMac (char *mac_str);

void checkPacketBegin (char * symbol, unsigned char type);
void checkPacketEnd (char * symbol);
cmd_t * checkSend (char * symbol, distribution_t * distr, distribution_t * snap);
list_t * checkCommand (list_t * list, cmd_t * cmd);
int elemExists (char * str);
void checkEthMac (char *mac_str, char src);
void checkEthMacVar (int);
void checkEthPayload (void);
void checkEthProtocol (unsigned long);
void checkEthFcsSize (unsigned int size);
void checkEthRxError (unsigned int rx);
mac_t * checkMac (char *mac_str);
unsigned char hexToChar (char c);
void printMac (unsigned char * mac);
void checkPosAddr (unsigned long addr);
void checkPosControl (unsigned long control);
void checkPosProtoSize (unsigned long size);
void checkPosProto (unsigned long proto);
//void checkPosPayload (distribution_t * distr);
void checkPosPayload (void);
void checkPosFcsSize (unsigned long size);
void checkPosRxError (unsigned int rx);
counter_t * getCounter (char * id);
void checkAddCounter (char * id, distribution_t * distr, unsigned int size);
void checkAtmType (unsigned char type);
void checkAtmGfc (distribution_t * distr);
void checkAtmVpi (distribution_t * distr);
void checkAtmVci (distribution_t * distr);
void checkAtmPt  (distribution_t * distr);
void checkAtmClp (distribution_t * distr);
void checkAtmPayload ();
void checkAal5Uu  (distribution_t * distr);
void checkAal5Cpi (distribution_t * distr);
void checkAal5Crc (distribution_t * distr);
void checkIBType (unsigned char type);
void checkIBVirtualLane(distribution_t *distr);
void checkIBLinkVersion(distribution_t *distr);
void checkIBServiceLevel(distribution_t *distr);
void checkIBSLID(distribution_t *distr);
void checkIBDLID(distribution_t *distr);
void checkIBOpcode(distribution_t *distr);
void checkIBTver(distribution_t *distr);
void checkIBDQP(distribution_t *distr);
void checkIBSQP(distribution_t *distr);
void checkIBPSN(distribution_t *distr);
void checkIBPayload ();
list_t * checkGroup (list_t * list, group_t * group);


%}

/* ------------------------------------------------------------------
   Yacc declarations
   ------------------------------------------------------------------ */
   
/* The structure for passing value between lexer and parser */
/* In the lexer we know it by the name 'yylval'				*/
%union {
   char *str;
   unsigned long l;
   void * distr;
   void * pload;
   void * list;
   void * command;
}

%token 	SEND SRC_ADDR DST_ADDR LENGTH STEP NORMAL POISSON UNIFORM CONSTANT
	OUTPUT_FILE VERBOSE RANDOM_SEED ADDRESS CONTROL PROTOCOL_SIZE 
	FCS_SIZE FORMAT_ERF TOKEN_SIZE DUMMY
	PROTOCOL PAYLOAD RX_ERROR FORMAT_PCAP
	ATM_GFC ATM_VPI ATM_VCI ATM_PT ATM_CLP AAL5_UU AAL5_CPI
	AAL5_CRC ATM_TYPE ATM_UNI ATM_NNI LOOP TOKEN_GROUP INTERFACE
	IB_LOCAL IB_GLOBAL IB_LRH_VL IB_LRH_LVER IB_LRH_SLEVEL IB_LRH_DLID IB_LRH_SLID IB_BTH_QP IB_SRC_QP  IB_BTH_OPCODE  IB_BTH_PSN IB_BTH_TVER IB_RAW IB_NON_IB
%token EOC PACKET PACKETS TRAFFIC COLON TILDE COMMA OPTIONS PLUS
	PACKET_ETH802_3 PACKET_POS OUTPUT_FORMAT COUNTERS PACKET_ETH_II
	PACKET_ATM PACKET_AAL5 WLEN SNAP PACKET_IB
%token OPEN_KEY CLOSE_KEY OPEN_PAR CLOSE_PAR OPEN_BRA CLOSE_BRA
%token <str> ID STRING TOKEN_MAC NUMBER HEXASTRING


/*%type <type> type simple_type cast*/
%type <l> number output_formats
%type <str> identifier mac string
%type <distr> distribution
%type <pload> payload_contents
%type <list>  traffic_commands traffic_groups
%type <command> t_command traffic_group

/*number p_parms*/
/* %expect 1 */ /* shift/reduce conflict: dangling ELSE */
                /*    declaration */
%%

/* ------------------------------------------------------------------
   Yacc grammar rules
   ------------------------------------------------------------------ */

program
	: options packets traffic
	;

options
	: OPTIONS OPEN_KEY option_parms CLOSE_KEY
	|
	;

option_parms
	: option_parms o_parms
	|
	;

o_parms
	: OUTPUT_FILE string EOC	{ strcpy (daggen_options.output_file, $2);
					  free($2); }
	| VERBOSE EOC 			{ daggen_options.verbose = 1; }
	| INTERFACE number EOC		{ daggen_options.interface_num = (int) $2; }
	| RANDOM_SEED number EOC	{ daggen_options.random_seed = (unsigned long) $2; }
	| OUTPUT_FORMAT output_formats EOC
		{ daggen_options.output_format = (unsigned char) $2; }
	;

output_formats
	: FORMAT_ERF	{ $$ = OUTPUT_FORMAT_ERF; }
	| FORMAT_PCAP	{ $$ = OUTPUT_FORMAT_PCAP; }
	;


packets
	: PACKETS OPEN_KEY counters packet_defs CLOSE_KEY
	;

counters
	: COUNTERS OPEN_KEY counter_defs CLOSE_KEY
	|
	;

counter_defs
	: counter_defs counter_d
	|
	;

counter_d
	: identifier distribution TOKEN_SIZE number EOC
		{ checkAddCounter ($1, $2, $4); }
	;

packet_defs
	: packet_defs packet
	|
	;

packet
	: PACKET PACKET_ETH802_3 identifier {checkPacketBegin($3,PKT_ETH802_3);}
		OPEN_KEY eth802_3_parms CLOSE_KEY {checkPacketEnd($3);}
	| PACKET PACKET_ETH_II identifier {checkPacketBegin($3,PKT_ETH_II);}
		OPEN_KEY eth_II_parms CLOSE_KEY {checkPacketEnd($3);}
	| PACKET PACKET_POS identifier {checkPacketBegin($3,PKT_POS);}
		OPEN_KEY pos_parms CLOSE_KEY {checkPacketEnd($3);}
	| PACKET PACKET_ATM identifier {checkPacketBegin($3,PKT_ATM);}
		OPEN_KEY atm_parms CLOSE_KEY {checkPacketEnd($3);}
	| PACKET PACKET_AAL5 identifier {checkPacketBegin($3,PKT_AAL5);}
		OPEN_KEY aal5_parms CLOSE_KEY {checkPacketEnd($3);}
	| PACKET PACKET_IB identifier {checkPacketBegin($3,PKT_IB);}
		OPEN_KEY infiniband_parms CLOSE_KEY {checkPacketEnd($3);}
	;


eth802_3_parms
	: eth802_3_parms eth802_3_p
	| 
	;
	
eth802_3_p
	: SRC_ADDR mac EOC	{ checkEthMac ($2,1); }
	| SRC_ADDR payload EOC  { checkEthMacVar (1); }
	| DST_ADDR mac EOC	{ checkEthMac ($2,0); }
	| DST_ADDR payload EOC  { checkEthMacVar (0); }
	| PAYLOAD payload EOC	{ checkEthPayload();  }
	| FCS_SIZE number EOC	{ checkEthFcsSize($2);}
	| RX_ERROR number EOC	{ checkEthRxError($2);}
	;

eth_II_parms
	: eth_II_parms eth_II_p
	|
	;

eth_II_p
	: SRC_ADDR mac EOC	{ checkEthMac ($2,1);    }
	| SRC_ADDR payload EOC  { checkEthMacVar (1);    }
	| DST_ADDR mac EOC	{ checkEthMac ($2,0);    }
	| DST_ADDR payload EOC  { checkEthMacVar (0);    }
	| PROTOCOL number EOC   { checkEthProtocol ($2); }
	| PAYLOAD payload EOC   { checkEthPayload ();    }
	| FCS_SIZE number EOC	{ checkEthFcsSize($2);   }
	;

pos_parms
	: pos_parms pos_p
	|
	;

pos_p
	: ADDRESS number EOC		{ checkPosAddr      ($2); }
	| CONTROL number EOC		{ checkPosControl   ($2); }
	| PROTOCOL_SIZE number EOC	{ checkPosProtoSize ($2); }
	| PROTOCOL number EOC		{ checkPosProto     ($2); }
	| PAYLOAD payload EOC		{ checkPosPayload   ();   }
	| FCS_SIZE number EOC           { checkPosFcsSize   ($2); }
	| RX_ERROR number EOC           { checkPosRxError   ($2); }
	;

atm_parms
	: atm_parms atm_p
	|
	;

atm_p
	: ATM_TYPE ATM_UNI EOC		{ checkAtmType (ATM_TYPE_UNI); 	}
	| ATM_TYPE ATM_NNI EOC		{ checkAtmType (ATM_TYPE_NNI); 	}
	| ATM_GFC distribution EOC	{ checkAtmGfc ($2);		}
	| ATM_VPI distribution EOC	{ checkAtmVpi ($2);		}
	| ATM_VCI distribution EOC	{ checkAtmVci ($2);		}
	| ATM_PT  distribution EOC	{ checkAtmPt  ($2);		}
	| ATM_CLP distribution EOC	{ checkAtmClp ($2);		}
	| PAYLOAD payload EOC		{ checkAtmPayload ();		}
	;

aal5_parms
	: aal5_parms aal5_p
	|
	;

aal5_p
	: ATM_TYPE ATM_UNI EOC		{ checkAtmType (ATM_TYPE_UNI); 	}
	| ATM_TYPE ATM_NNI EOC		{ checkAtmType (ATM_TYPE_NNI); 	}
	| ATM_GFC distribution EOC	{ checkAtmGfc ($2);		}
	| ATM_VPI distribution EOC	{ checkAtmVpi ($2);		}
	| ATM_VCI distribution EOC	{ checkAtmVci ($2);		}
	| ATM_PT  distribution EOC	{ checkAtmPt  ($2);		}
	| ATM_CLP distribution EOC	{ checkAtmClp ($2);		}
	| PAYLOAD payload EOC		{ checkAtmPayload ();		}
	| AAL5_UU  distribution EOC	{ checkAal5Uu  ($2);		}
	| AAL5_CPI distribution EOC	{ checkAal5Cpi ($2);		}
	| AAL5_CRC distribution EOC	{ checkAal5Crc ($2);		}
	;

infiniband_parms
	: infiniband_parms infiniband_p
	| 
        ;
infiniband_p
	: ATM_TYPE IB_GLOBAL EOC 	{checkIBType(IB_TYPE_GLOBAL);}	
	| ATM_TYPE IB_LOCAL EOC 	{checkIBType(IB_TYPE_LOCAL);}	
    | ATM_TYPE IB_RAW EOC 	{checkIBType(IB_TYPE_RAW);}	
	| ATM_TYPE IB_NON_IB EOC 	{checkIBType(IB_TYPE_NONIB);}
	| IB_LRH_VL distribution EOC	{checkIBVirtualLane( $2);}
	| IB_LRH_LVER distribution EOC {checkIBLinkVersion($2);}
	| IB_LRH_SLID distribution EOC {checkIBSLID($2);}
	| IB_LRH_DLID distribution EOC {checkIBDLID($2);}
	| IB_LRH_SLEVEL distribution EOC {checkIBServiceLevel($2);}
	| IB_BTH_OPCODE distribution EOC {checkIBOpcode($2);}
	| IB_BTH_PSN  distribution EOC {checkIBPSN($2);}
	| IB_BTH_QP distribution EOC {checkIBDQP($2);}
	| IB_SRC_QP distribution EOC {checkIBSQP($2);}
	| IB_BTH_TVER distribution EOC {checkIBTver($2);}
	| PAYLOAD payload EOC		{ checkIBPayload ();}
	;
mac
	: TOKEN_MAC {$$ = $1;}
	;

distribution
	: number
		{$$ = (distribution_t *) distrNew (_CONSTANT, (unsigned int) $1, 0, 0, NULL);}
	| OPEN_BRA number COLON number CLOSE_BRA
		{$$ = (distribution_t *) distrNew (_PATTERN_ROUND, $2, $4, 1, NULL);}
	| OPEN_BRA number TILDE number CLOSE_BRA
		{$$ = (distribution_t *) distrNew (_PATTERN_BOUNCE, $2, $4, 1, NULL);}
	| OPEN_BRA number COLON number CLOSE_BRA STEP distribution
		{$$ = (distribution_t *) distrNew (_PATTERN_ROUND, $2, $4, 0, $7);}
	| OPEN_BRA number TILDE number CLOSE_BRA STEP distribution
		{$$ = (distribution_t *) distrNew (_PATTERN_BOUNCE, $2, $4, 0, $7);}
	| CONSTANT OPEN_PAR number CLOSE_PAR
		{$$ = (distribution_t *) distrNew (_CONSTANT, $3, 0, 0, NULL);}
	| UNIFORM  OPEN_PAR number COMMA number CLOSE_PAR
		{$$ = (distribution_t *) distrNew (_UNIFORM, $3, $5, 0, NULL);}
	| NORMAL   OPEN_PAR number COMMA number CLOSE_PAR
		{$$ = (distribution_t *) distrNew (_NORMAL, $3, $5, 0, NULL);}
	| POISSON  OPEN_PAR number COMMA number CLOSE_PAR
		{$$ = (distribution_t *) distrNew (_POISSON, $3, $5, 0, NULL);}
	;

payload
	: payload PLUS payload_contents
		{ pload = (payload_t *) $3;
		 listAdd (payload_list, pload, 0); }
	| payload_contents
		{ pload = (payload_t *) $1;
		  payload_list = listNew(payload_list);
		  listAdd (payload_list, pload, 0); }
	;

payload_contents
	: HEXASTRING
		{pload = payloadNew (PLOAD_HEXASTRING, $1, NULL);
		 $$ = pload;}
	| identifier
		{pload =  payloadNew (PLOAD_COUNTER,
		(counter_t *) getCounter($1), NULL);
		$$ = pload; }
	| identifier OPEN_PAR distribution CLOSE_PAR
		{pload =  payloadNew (PLOAD_COUNTER,
		(counter_t *) getCounter($1), $3);
		$$ = pload; }
	| identifier OPEN_BRA distribution CLOSE_BRA
		{pload = payloadNew (PLOAD_COUNTER_MASK,
		(counter_t *) getCounter($1), $3);
		$$ = pload; }
	| DUMMY OPEN_PAR distribution CLOSE_PAR
		{pload =  payloadNew (PLOAD_DUMMY, $3, NULL); $$ = pload;}
	| WLEN
		{ $$ = payloadNew (PLOAD_WLEN, NULL, NULL); }
	;

traffic
	: TRAFFIC OPEN_KEY traffic_groups CLOSE_KEY { group_list = (list_t *) $3; }
	;

traffic_groups
	: traffic_groups traffic_group
		{ $$ = checkGroup ( (list_t *) $<list>1, (group_t *) $2); }
	|	{ $$ = NULL; }
	;

traffic_group
	: TOKEN_GROUP identifier OPEN_KEY traffic_commands CLOSE_KEY
		{ $$ = groupNew ( (char *) $2, (list_t *) $4 ); }
	;

traffic_commands
	: traffic_commands t_command
	  { $$ = checkCommand ((list_t *) $<list>1, (cmd_t *) $2); }
	| { $$ = NULL; }
	;

t_command
	: SEND identifier distribution EOC
		{ $$ = checkSend ((char *)$2, (distribution_t *)$3, NULL); }
	| SEND identifier distribution SNAP distribution EOC
		{ $$ = checkSend ((char *)$2, (distribution_t *)$3, (distribution_t *)$5); }
	| LOOP distribution OPEN_KEY traffic_commands CLOSE_KEY
		{ $$ = cmdNew (CMDLOOP, (distribution_t *) $2, (list_t *) $4, NULL); }
	;

number
	: NUMBER { $$ = (unsigned long) $1; }
	;

string
	: STRING { $$ = $1; }
	;

identifier
	: ID { $$ = $1; }
	;




%%
/* ------------------------------------------------------------------
   Additional code (again copied verbatim to the output file)
   ------------------------------------------------------------------ */

//
// Check packet construction
//

void checkPacketBegin (char * symbol, unsigned char type) {
	if (elemExists(symbol)) {
		printf ("Warning: packet '%s' already declared (omitting) at line %d\n",
			symbol, lineno);
		bypass = 1;
		free(symbol);

	} else {
		packet = packetNew (type, symbol);
		listAdd (list, symbol, 0);
		listAdd (packet_list, packet, 0);
	}
}

void checkPacketEnd (char * symbol) {
	if (!bypass) {
		//packetFree(packet);
	}
	bypass = 0;
	//free (symbol);
}

//
// Check commands
//

cmd_t * checkSend (char * symbol, distribution_t * distr, distribution_t * snap) {
	cmd_t * cmd = NULL;

	if (elemExists(symbol)) {
		cmd = cmdNew (CMDSEND, distr, strdup(symbol), snap);
		//printf("[checkSend] cmd->ptr: \"%s\"\n", (char *) cmd->ptr);
	} else {
		printf ("Warning: packet '%s' not declared (omitting) at line %d\n",
			symbol, lineno);
	}

	return cmd;
}

list_t * checkCommand (list_t * list, cmd_t * cmd) {
	if (list == NULL)
		list = listNew();

	listAdd (list, cmd, 0);
	return list;
}

list_t * checkGroup (list_t * list, group_t * group) {
	group_t * aux;
	char found = 0;

	if (list == NULL) {
		list = listNew();
		listAdd (list, group, 0);
	} else {
		listPtrBegin(list);
		while (listHasMoreElements(list) && !found) {
			aux = (group_t *) listGetPtrElem(list);
			found = !strcmp (group->id, aux->id);
			listPtrNext(list);
		}

		if(found)
			printf ("Traffic group '%s' already declared (omitting)\n",
				group->id);
		else
			listAdd (list, group, 0);
	}

	return list;
}

//
// Is the element in the symbol list? (identified by a string)
//

int elemExists (char * str) {
	int found = 0;
	char * aux;

	listPtrBegin(list);
	while (listHasMoreElements(list) && !found) {
		aux = (char *)listGetPtrElem(list);
		found = !strcmp (str, aux);
		listPtrNext(list);
	}
	return found;
}

//
// Ethernet 802.3 comprobations
//

void checkEthMac (char *mac_str, char src) {
	// Eth802.3, EthII and others are compatible
	packet_eth_t * p;

	if (!bypass) {
		p = (packet_eth_t *) packet->p;
		if (src) {
			free(p->src_addr);
			p->src_addr = checkMac (mac_str);
			p->src_addr_type = MAC_STATIC;
		} else {
			free(p->dst_addr);
			p->dst_addr = checkMac (mac_str);
			p->dst_addr_type = MAC_STATIC;
		}
	}
}

// Mac checking is done when we are generating the ERF record (toerf.c)
void checkEthMacVar (int src) {
	// Eth802.3, EthII and others are compatible
	packet_eth_t * p;

	if (!bypass) {
		p = (packet_eth_t *) packet->p;
		if (src) {
			if (p->src_addr_var != NULL) free(p->src_addr_var);
			p->src_addr_var = payload_list; // is not a payload, but a mac address
			p->src_addr_type = MAC_VARIABLE;
		} else {
			if (p->dst_addr_var != NULL) free(p->dst_addr_var);
			p->dst_addr_var = payload_list; // is not a payload, but a mac address
			p->dst_addr_type = MAC_VARIABLE;
		}
	}
}

void checkEthPayload () {
	packet_eth_t * p;

	if (!bypass) {
		p = (packet_eth_t *) packet->p;
		p->payload = payload_list;
	}
}

void checkEthProtocol (unsigned long proto) {
	packet_eth_II_t * p; //only this one has a protocol field

	if (!bypass) {
		p = (packet_eth_II_t *) packet->p;
		if (proto > 65535) {
			if (daggen_options.verbose)
				printf("Ethernet protocol field too high, kept at 65535\n");
			p->protocol = (unsigned short int) 65535;
		} else {
			p->protocol = (unsigned short int) proto;
		}
	}
}

void checkEthFcsSize (unsigned int size) {
	packet_eth_t * p;

	if (!bypass) {
		p = (packet_eth_t *) packet->p;
		if (size != 0 && size != 2 && size != 4 && size != 6) {
			if (daggen_options.verbose)
				printf ("Wrong ethernet FCS size. Should be 0, 2 or 4 bytes, 6 for wrong 4-byte CRC. Kept at 0\n");
			size = 0;
		}
		p->fcs_size = size;
	}
}

void checkEthRxError (unsigned int rx) {
	packet_eth_t * p;

	if (!bypass) {
		p = (packet_eth_t *) packet->p;
		if (rx != 0 && rx != 1) {
			if (daggen_options.verbose)
				printf ("Wrong RX ERROR. Should be 0(OFF) or 1(ON). Kept at 0\n");
			rx = 0;
		}
		p->rx_error = rx;
	}
}


//
// Check MAC
//

mac_t * checkMac (char *mac_str) {
	int i;
	mac_t * mac;

	mac = macNew();
	mac->type = MAC_STATIC;
	for (i=0; i<6; i++)
		mac->mac[i] = hexToChar(mac_str[i*3])<<4 | hexToChar(mac_str[i*3+1]);

	for (i=0; i<6; i++) {
		if(mac_str[i*3] == '*') {

			BITSET(mac->bitset,(i*2)+1);
			mac->type = MAC_WILDCARD;
		}
		if(mac_str[i*3+1] == '*') {
			BITSET(mac->bitset,(i*2)+2);
			mac->type = MAC_WILDCARD;
		}
	}

	return mac;
}

//
// Hexadecimal character to byte
//

unsigned char hexToChar (char c) {
	unsigned char res;

	res = 0;
	switch (c) {
		case '*':
		case '0': res = 0;
			break;
		case '1': res = 1;
			break;
		case '2': res = 2;
			break;
		case '3': res = 3;
			break;
		case '4': res = 4;
			break;
		case '5': res = 5;
			break;
		case '6': res = 6;
			break;
		case '7': res = 7;
			break;
		case '8': res = 8;
			break;
		case '9': res = 9;
			break;
		case 'A':
		case 'a': res = 10;
			break;
		case 'B':
		case 'b': res = 11;
			break;
		case 'C':
		case 'c': res = 12;
			break;
		case 'D':
		case 'd': res = 13;
			break;
		case 'E':
		case 'e': res = 14;
			break;
		case 'F':
		case 'f': res = 15;
			break;
	}

	return res;
}

//
// Print MAC (for debugging purposes only)
//

void printMac (unsigned char * mac) {
	printf("[MAC] %02x:%02x:%02x:%02x:%02x:%02x\n",
		mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
}

//
// POS
//

void checkPosAddr (unsigned long addr) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (addr > 0xff) {
			if (daggen_options.verbose)
				printf("POS address too high, kept at 0xff\n");
			p->address = (unsigned char) 0xff;
		} else {
			p->address = (unsigned char) addr;
		}
	}
}

void checkPosControl (unsigned long control) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (control > 0xff) {
			if (daggen_options.verbose)
				printf("POS control field too high, kept at 0xff\n");
			p->control = (unsigned char) 0xff;
		} else {
			p->control = (unsigned char) control;
		}
	}
}

void checkPosProtoSize (unsigned long size) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (size != 1 && size != 2) {
			if (daggen_options.verbose)
				printf("POS protocol field size can only be 1 or 2 bytes, kept at 2 bytes (default)\n");
			p->protocol_size = (unsigned char) 2;
		} else {
			p->protocol_size = (unsigned char) size;
		}
	}
}

void checkPosProto (unsigned long proto) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (proto > 65535) {
			if (daggen_options.verbose)
				printf("POS protocol field too high, kept at 65535\n");
			p->protocol = (unsigned short int) 65535;
		} else {
			p->protocol = (unsigned short int) proto;
		}
	}
}

void checkPosPayload () {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		p->payload = payload_list;
	}
}

void checkPosFcsSize (unsigned long size) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (size != 0 && size != 2 && size != 4 && size != 6) {
			if (daggen_options.verbose)
				printf("POS FCS field size can only be 0, 2 or 4 bytes, 6 for a wrong 4-byte CRC. Kept at 4 bytes (default)\n");
			p->fcs_size = (unsigned char) 4;
		} else {
			p->fcs_size = (unsigned char) size;
		}
	}
}

void checkPosRxError (unsigned int rx) {
	packet_pos_t * p;

	if (!bypass) {
		p = (packet_pos_t *) packet->p;
		if (rx != 0 && rx != 1) {
			if (daggen_options.verbose)
				printf ("Wrong RX ERROR. Should be 0(OFF) or 1(ON). Kept at 0\n");
			rx = 0;
		}
		p->rx_error = rx;
	}
}

//
// ATM
//

void checkAtmType (unsigned char type) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	p->type = type;
}

void checkAtmGfc (distribution_t * distr) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	free (p->gfc);
	p->gfc = distr;
}

void checkAtmVpi (distribution_t * distr) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	free (p->vpi);
	p->vpi = distr;
}

void checkAtmVci (distribution_t * distr) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	free (p->vci);
	p->vci = distr;
}

void checkAtmPt  (distribution_t * distr) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	free (p->pt);
	p->pt = distr;
}

void checkAtmClp (distribution_t * distr) {
	packet_atm_t * p;

	p = (packet_atm_t *) packet->p;
	free (p->clp);
	p->clp = distr;
}

void checkAtmPayload () {
	packet_atm_t * p;

	if (!bypass) {
		p = (packet_atm_t *) packet->p;
		p->payload = payload_list;
	}
}

void checkAal5Uu  (distribution_t * distr) {
	packet_aal5_t * p;

	p = (packet_aal5_t *) packet->p;
	free (p->uu);
	p->uu = distr;
}

void checkAal5Cpi (distribution_t * distr) {
	packet_aal5_t * p;

	p = (packet_aal5_t *) packet->p;
	free (p->cpi);
	p->cpi = distr;
}

void checkAal5Crc (distribution_t * distr) {
	packet_aal5_t * p;

	p = (packet_aal5_t *) packet->p;
	free (p->crc);
	p->crc = distr;
}

//
// Counters stuff
//

counter_t * getCounter (char * id) {
	int found = 0;
	counter_t * aux;

	aux = NULL;
	listPtrBegin(counter_list);
	while (listHasMoreElements(counter_list) && !found) {
		aux = (counter_t *)listGetPtrElem(counter_list);
		found = !strcmp (id, aux->id);
		listPtrNext(counter_list);
	}

	if (!found) {
		printf ("Warning: counter \"%s\" not declared in line %d (omitting)\n"
			, id, lineno);
		return NULL;
	} else {
		return aux;
	}

}

void checkAddCounter (char * id, distribution_t * distr, unsigned int size) {
	int found = 0;
	counter_t * aux;

	listPtrBegin(counter_list);
	while (listHasMoreElements(counter_list) && !found) {
		aux = (counter_t *)listGetPtrElem(counter_list);
		found = !strcmp (id, aux->id);
		listPtrNext(counter_list);
	}

	// BUG: Check size

	if (!found) {
		if (size != 1 && size !=2 && size != 4) {
			printf ("Warning: counter \"%s\" size can only be 1, 2 or 4 bytes (line %d)\n", id, lineno);
		} else {
			aux = counterNew (id, distr, size);
			listAdd (counter_list, aux, 0);
		}

	} else {
		printf ("Warning: counter \"%s\" already declared un line %d (omitting)\n",
			id, lineno);
	}
}
void checkIBVirtualLane(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->lrh_vl);
    p->lrh_vl = distr;
    return ;
}
void checkIBLinkVersion(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->lrh_lver);
    p->lrh_lver = distr;
    return ;

}
void checkIBSLID(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->lrh_slid);
    p->lrh_slid = distr;
    return ;
}
void checkIBDLID(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->lrh_dlid);
    p->lrh_dlid = distr;
    return ;
}


void checkIBType (unsigned char type) {
	packet_ib_t * p;

	p = (packet_ib_t *) packet->p;
	p->type = type;
}

void checkIBOpcode(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->bth_opcode);
    p->bth_opcode = distr;
    return ;
}
void checkIBTver(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->bth_tver);
    p->bth_tver = distr;
    return ;
}
void checkIBDQP(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->bth_qp);
    p->bth_qp = distr;
    return ;
}

void checkIBSQP(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->src_qp);
    p->src_qp = distr;
    return ;
}
void checkIBPSN(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->bth_psn);
    p->bth_psn = distr;
    return ;
}


void checkIBServiceLevel(distribution_t *distr)
{
    packet_ib_t *p;

    p = (packet_ib_t *) packet->p;
    free (p->lrh_slevel);
    p->lrh_slevel = distr;
    return ;
}


void checkIBPayload ()
{
packet_ib_t* p;

	if (!bypass) {
		p = (packet_ib_t *) packet->p;
		p->payload = payload_list;
	}
}
