#include <stdio.h>
#include "iso8583.h"
#include "convert.h"
#define LS_MAP_BIT 0x80
extern unsigned char tpdu[];
/***************************************************************************/
/* This table must contain all the pairs which are use by the application */
/* to transform the data. The embedded defines establish the convert table */
/* indicies which are used in field_table (see tables.h). */
/***************************************************************************/
converters convert_table [] = {
#define ASC_ASC 0
{ asc_to_asc, asc_to_asc },
#define AV3_AV3 1
{ av3_to_av3, av3_to_av3 },
#define BIT_BIT 2
{ bit_to_bit, bit_to_bit },
#define BCD_BCD 3
{ bcd_to_bcd, bcd_to_bcd },
#define BCD_ASC 4
{ asc_to_bcd, bcd_to_asc },
#define ASC_STR 5
{ str_to_asc, asc_to_str },
#define BCD_STR 6
{ str_to_bcd, bcd_to_str },
#define BCD_SNZ 7
{ str_to_bcd, bcd_to_snz },
#define AV2_STR 8
{ str_to_av2, av2_to_str },
#define BV2_STR 9
{ str_to_bv2, bv2_to_str },
#define AV3_STR 10
{ str_to_av3, av3_to_str },
#define XBC_STR 11
{ str_to_xbc, xbc_to_str },
#define BV3_STR 12
{ str_to_bv3, bv3_to_str }
};
/***************************************************************************
The least significant 4 bits of the following byte will be used to pad
an odd length packed item in the final nibble. The default is zero.
***************************************************************************/
unsigned char pad_nibble_8583 = 0;
int fn_8583; /* Field number */
unsigned char *src_8583; /* Source pointer */
unsigned char *dst_8583; /* Destination pointer */
unsigned char map_8583[BIT_MAP_SIZE]; /* Map */
field_struct *field_ptr;
int Map_Test(map, field_no)
unsigned char *map;
int field_no;
{
if (field_no >= 1 && field_no <= 64)
{
map += (--field_no >> 3); /* point at proper byte */
return(*map & (LS_MAP_BIT >> (field_no & 7))); /* form proper mask */
}
else
return( 0 );
}
/* map_reset
Reset a particular bit.
*/
void Map_Reset(map, field_no)
unsigned char *map;
int field_no;
{
if (field_no >= 1 && field_no <= 64)
{
map += (--field_no >> 3);
*map &= ~(LS_MAP_BIT >> (field_no & 7));
}
}
/***************************************************************************
Determine the size of the bit map and save it in map_8583.
***************************************************************************/
int capture_map( start )
unsigned char *start;
{
int n = 0;
unsigned char *map_ptr;
unsigned char map_byte;
map_ptr = start;
do
{
map_byte = *map_ptr; /* Fetch first byte of map */
map_ptr += BIT_MAP_SIZE; /* Skip over this map section */
n += BIT_MAP_SIZE;
}
while ( map_byte & LS_MAP_BIT ); /* continue if multiple maps */
memcpy( map_8583, start, n ); /* save map in map_8583 global */
return( n );
}
/***************************************************************************
This is the main 8583 field processing function.
Return values:
-1 Field not defined in field table.
-2 Stored more in buffer than limit.
-3 Exceeded size of valid data in buffer.
-4 Stored more than variable limit on an incomming message.
-5 No matching variant field definition.
>0 Assembly: number of bytes put into buffer. Use for write.
Disassembly: Number of bytes in buffer not processed.
Should be zero.
***************************************************************************/
int process_iso8583( how, field_tbl, map, buffer, limit )
int how; /* how=0 => pack, how=1 => unpack */
field_struct *field_tbl; /* pointer to field table */
unsigned char *map; /* pointer to map. Ignored on incomming. */
unsigned char *buffer; /* pointer to buffer */
int limit; /* limit on assembly. size on disassembly */
{
int map_mask; /* mask for testing map bits */
int n,pp; /* number of bytes in map */
int rst; /* result of processing a single field */
unsigned char *map_ptr;
/* Initialize pointer to field table */
field_ptr = field_tbl;
/* Capture either from parameter or buffer */
/* Copy map to map_8583 return size */
n = capture_map((how==0)?map:buffer+7);
/* Initialize source and destination pointers */
src_8583 = buffer;
dst_8583 = buffer;
fn_8583 = 0;
process_field(how, buffer); /* TPDU */
process_field(how, buffer); /* Message type */
/* MODIFICATION TO RECOGNISE TPDU BEGINNING WITH 68 - NMS MESSAGE */
/* if incoming map and NMS then just return as valid response and */
/* allow higher level routine to take care! */
if ((how == 1) && ((tpdu[1]&0xff) == 0x68))
{ puts("BACK!");
return(-6); /* bytes remaining */
}
if (how==0)
{
memcpy(buffer+7, map_8583, n); /* store outgoing map */
dst_8583 = buffer+7+n; /* initialize destination */
}
else
{
memcpy(map, map_8583, n); /* return received map */
src_8583 = buffer+7+n; /* initialize source */
}
for (fn_8583=1,map_ptr=map_8583; n; n--,map_ptr++)
{
for (map_mask=LS_MAP_BIT; map_mask; map_mask>>=1,fn_8583++)
{
if (*map_ptr & map_mask)
{
rst = process_field(how,buffer);
if (rst != 0)
return( rst );
if (how == 0)
{
if ((dst_8583-buffer) > limit)
return( -2 );
}
else if ((src_8583-buffer) > limit)
{
puts("PUTSA!");
return( -3 );
}
}
}
}
if (how == 0)
return( dst_8583-buffer ); /* bytes put into buffer */
else return( limit-(int)(src_8583-buffer) ); /* bytes remaining */
}
/***************************************************************************
Process a single field in the field table.
***************************************************************************/
int process_field( how, buffer )
int how; /* how=0 => pack, how=1 => unpack */
unsigned char *buffer; /* pointer to buffer */
{
int ci;
int psz;
int vsz;
unsigned char *sv_dst;
int (*func_ptr) ();
/* advance to corresponding field in table */
while ((field_ptr->field_num & FIELD_MASK) != fn_8583)
{
/* Received a field which isnt defined */
if (field_ptr->field_num & STOP)
{
puts("BACK!");
return( -1 );
}
memset((char *)(field_ptr->reference),0,field_ptr->var_sz);
field_ptr++;
}
ci = field_ptr->convert_idx;
if (ci == VARIANT)
{
psz = do_variant(how,return_variant1(),return_variant2(),&ci,&vsz);
if (psz < 0)
return( psz );
}
else
if (ci == COMPUTE)
{
func_ptr = (int ((*)()))(field_ptr->reference);
ci = (*func_ptr)(how, buffer, &psz, &vsz);
}
else
{
psz = field_ptr->packet_sz;
vsz = field_ptr->var_sz;
if (how == 0)
src_8583 = (unsigned char *)field_ptr->reference;
else dst_8583 = (unsigned char *)field_ptr->reference;
}
sv_dst = dst_8583; /* save destination before transfer */
(*convert_table[ci][how])( psz ); /* call the proper convert function */
if (how == 1) /* unpacking */
{
if ((dst_8583 - sv_dst) > vsz) /* stored more than limit */
return( -4 );
}
field_ptr++;
return( 0 );
}
/***************************************************************************
Process a variant field. Returns packet size field or negative on error.
***************************************************************************/
int do_variant( how, v1, v2, ci, vsz )
int how; /* how=0 => pack, how=1 => unpack */
unsi