#include <string.h>
#include <syslog.h>
#include <libusb.h>
#include "usb_eap.h"
#include "wimax.h"

#if EAP_OVER_USB == 1

void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags);

extern struct eap_type_handler eaphandlers[];
extern char cipher_id;
extern int usb_eap_disconnect(void);

int eap_find_type(int eap_type);
int tls_funcs_init(struct generic_eap_data *thisint);
int tls_funcs_load_user_cert(struct generic_eap_data *thisint, char *client_cert, char *key_file, char *password,
			                 char *random_file);
int if_up();
int link_down();

uint8_t *tls_crypt_gen_keyblock(struct generic_eap_data *thisint, char *sesskey,
			      int sesskeylen);

struct config_network *config_get_network_config();
int xsup_assert(int condition, char *desc, int flag)
{
    if(condition) return TRUE;
    WIMAX_PRINT(LOG_ERR, "%s", desc);
    //if(flag) GeAssert(0);
    if(flag){
		while(1)printf("[Wijet] xsup_assert\r\n");
	}
    return FALSE;
}

void tls_funcs_process_error()
{
  unsigned long err;

  err = ERR_get_error();
  if (err != 0)
  {
      debug_printf(DEBUG_NORMAL, "OpenSSL Error -- %s\n", ERR_error_string(err, NULL));
      debug_printf(DEBUG_NORMAL, "Library  : %s\n", ERR_lib_error_string(err));
      debug_printf(DEBUG_NORMAL, "Function : %s\n", ERR_func_error_string(err));
      debug_printf(DEBUG_NORMAL, "Reason   : %s\n", ERR_reason_error_string(err));
  }
}

#if 0 //fanny

static char * strdup(const char *str)
{
	char *ret;
	int n;

	if (str == NULL) return(NULL);

	n=strlen(str);
	ret = (char *)malloc(n+1);
	if (ret == NULL) 
	{
		return(NULL);
	}
    memset(ret, 0, n+1);		
	memcpy(ret,str,n+1);
	return(ret);
}

#endif


/** 
 *	The following code is copied from : mp/chap_ms.c. We need to use : ChapMS2_NT()
 */

#include <openssl/des.h>
//#include <openssl/md4.h>
#define MD4_SIGNATURE_SIZE  	16  /* 16 bytes in a MD4 message digest */
#define MAX_NT_PASSWORD         256        /* Max (Unicode) chars in an NT pass */
#define SHA1_SIGNATURE_SIZE 	20

#define	_HTTP_OVER_SSL_			1


typedef struct {
    u_int32_t state[5];
    u_int32_t count[2];
    unsigned char buffer[64];
} SHA1_CTX;


/* MDstruct is the data structure for a message digest computation.
*/
typedef struct {
    unsigned int buffer[4]; /* Holds 4-word result of MD computation */
    unsigned char count[8]; /* Number of bits processed so far */
    unsigned int done;      /* Nonzero means MD computation finished */
} MD4_CTX;


/* Compile-time declarations of MD4 "magic constants".
*/
#define I0  0x67452301       /* Initial values for MD buffer */
#define I1  0xefcdab89
#define I2  0x98badcfe
#define I3  0x10325476
#define C2  013240474631     /* round 2 constant = sqrt(2) in octal */
#define C3  015666365641     /* round 3 constant = sqrt(3) in octal */

/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
** Table 2, page 660.
*/

#define fs1  3               /* round 1 shift amounts */
#define fs2  7
#define fs3 11
#define fs4 19
#define gs1  3               /* round 2 shift amounts */
#define gs2  5
#define gs3  9
#define gs4 13
#define hs1  3               /* round 3 shift amounts */
#define hs2  9
#define hs3 11
#define hs4 15


/* Compile-time macro declarations for MD4.
** Note: The "rot" operator uses the variable "tmp".
** It assumes tmp is declared as unsigned int, so that the >>
** operator will shift in zeros rather than extending the sign bit.
*/
#define f(X,Y,Z)             ((X&Y) | ((~X)&Z))
#define g(X,Y,Z)             ((X&Y) | (X&Z) | (Y&Z))
#define h(X,Y,Z)             (X^Y^Z)
#define rot(X,S)             (tmp=X,(tmp<<S) | (tmp>>(32-S)))
#define ff(A,B,C,D,i,s)      A = rot((A + f(B,C,D) + X[i]),s)
#define gg(A,B,C,D,i,s)      A = rot((A + g(B,C,D) + X[i] + C2),s)
#define hh(A,B,C,D,i,s)      A = rot((A + h(B,C,D) + X[i] + C3),s)



/* MD4Init(MDp)
** Initialize message digest buffer MDp.
** This is a user-callable routine.
*/
void
MD4Init(MDp)
MD4_CTX *MDp;
{
  int i;
  MDp->buffer[0] = I0;
  MDp->buffer[1] = I1;
  MDp->buffer[2] = I2;
  MDp->buffer[3] = I3;
  for (i=0;i<8;i++) MDp->count[i] = 0;
  MDp->done = 0;
}

/* MDblock(MDp,X)
** Update message digest buffer MDp->buffer using 16-word data block X.
** Assumes all 16 words of X are full of data.
** Does not update MDp->count.
** This routine is not user-callable.
*/
static void
MDblock(MDp,Xb)
MD4_CTX *MDp;
unsigned char *Xb;
{
  register unsigned int tmp, A, B, C, D;
  unsigned int X[16];
  int i;

  for (i = 0; i < 16; ++i) {
    X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24);
    Xb += 4;
  }

  A = MDp->buffer[0];
  B = MDp->buffer[1];
  C = MDp->buffer[2];
  D = MDp->buffer[3];
  /* Update the message digest buffer */
  ff(A , B , C , D ,  0 , fs1); /* Round 1 */
  ff(D , A , B , C ,  1 , fs2);
  ff(C , D , A , B ,  2 , fs3);
  ff(B , C , D , A ,  3 , fs4);
  ff(A , B , C , D ,  4 , fs1);
  ff(D , A , B , C ,  5 , fs2);
  ff(C , D , A , B ,  6 , fs3);
  ff(B , C , D , A ,  7 , fs4);
  ff(A , B , C , D ,  8 , fs1);
  ff(D , A , B , C ,  9 , fs2);
  ff(C , D , A , B , 10 , fs3);
  ff(B , C , D , A , 11 , fs4);
  ff(A , B , C , D , 12 , fs1);
  ff(D , A , B , C , 13 , fs2);
  ff(C , D , A , B , 14 , fs3);
  ff(B , C , D , A , 15 , fs4);
  gg(A , B , C , D ,  0 , gs1); /* Round 2 */
  gg(D , A , B , C ,  4 , gs2);
  gg(C , D , A , B ,  8 , gs3);
  gg(B , C , D , A , 12 , gs4);
  gg(A , B , C , D ,  1 , gs1);
  gg(D , A , B , C ,  5 , gs2);
  gg(C , D , A , B ,  9 , gs3);
  gg(B , C , D , A , 13 , gs4);
  gg(A , B , C , D ,  2 , gs1);
  gg(D , A , B , C ,  6 , gs2);
  gg(C , D , A , B , 10 , gs3);
  gg(B , C , D , A , 14 , gs4);
  gg(A , B , C , D ,  3 , gs1);
  gg(D , A , B , C ,  7 , gs2);
  gg(C , D , A , B , 11 , gs3);
  gg(B , C , D , A , 15 , gs4);
  hh(A , B , C , D ,  0 , hs1); /* Round 3 */
  hh(D , A , B , C ,  8 , hs2);
  hh(C , D , A , B ,  4 , hs3);
  hh(B , C , D , A , 12 , hs4);
  hh(A , B , C , D ,  2 , hs1);
  hh(D , A , B , C , 10 , hs2);
  hh(C , D , A , B ,  6 , hs3);
  hh(B , C , D , A , 14 , hs4);
  hh(A , B , C , D ,  1 , hs1);
  hh(D , A , B , C ,  9 , hs2);
  hh(C , D , A , B ,  5 , hs3);
  hh(B , C , D , A , 13 , hs4);
  hh(A , B , C , D ,  3 , hs1);
  hh(D , A , B , C , 11 , hs2);
  hh(C , D , A , B ,  7 , hs3);
  hh(B , C , D , A , 15 , hs4);
  MDp->buffer[0] += A;
  MDp->buffer[1] += B;
  MDp->buffer[2] += C;
  MDp->buffer[3] += D;
}


/* MD4Update(MDp,X,count)
** Input: X -- a pointer to an array of unsigned characters.
**        count -- the number of bits of X to use.
**          (if not a multiple of 8, uses high bits of last byte.)
** Update MDp using the number of bits of X given by count.
** This is the basic input routine for an MD4 user.
** The routine completes the MD computation when count < 512, so
** every MD computation should end with one call to MD4Update with a
** count less than 512.  A call with count 0 will be ignored if the
** MD has already been terminated (done != 0), so an extra call with
** count 0 can be given as a "courtesy close" to force termination
** if desired.
*/
void
MD4Update(MDp,X,count)
MD4_CTX *MDp;
unsigned char *X;
unsigned int count;
{
  unsigned int i, tmp, bit, byte, mask;
  unsigned char XX[64];
  unsigned char *p;

  /* return with no error if this is a courtesy close with count
  ** zero and MDp->done is true.
  */
  if (count == 0 && MDp->done) return;
  /* check to see if MD is already done and report error */
  if (MDp->done)
  { 
    #if MP_DEBUG_LEVEL>0
//      Print("\nError: MD4Update MD already done."); 
    #endif
      return; 
  }

  /* Add count to MDp->count */
  tmp = count;
  p = MDp->count;
  while (tmp)
  { tmp += *p;
  *p++ = tmp;
  tmp = tmp >> 8;
  }

  /* Process data */
  if (count == 512)
  { /* Full block of data to handle */
    MDblock(MDp,X);
  }
  else if (count > 512) /* Check for count too large */
  {
    #if MP_DEBUG_LEVEL>0
//        Print("\nError: MD4Update called with illegal count value %d.",
//             count);
    #endif
    return;
  }
  else /* partial block -- must be last block so finish up */
  {
    /* Find out how many bytes and residual bits there are */
    byte = count >> 3;
    bit =  count & 7;
    /* Copy X into XX since we need to modify it */
    for (i=0;i<=byte;i++)   XX[i] = X[i];
    for (i=byte+1;i<64;i++) XX[i] = 0;
    /* Add padding '1' bit and low-order zeros in last byte */
    mask = 1 << (7 - bit);
    XX[byte] = (XX[byte] | mask) & ~( mask - 1);
    /* If room for bit count, finish up with this block */
    if (byte <= 55)
    {
      for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
      MDblock(MDp,XX);
    }
    else /* need to do two blocks to finish up */
    {
      MDblock(MDp,XX);
      for (i=0;i<56;i++) XX[i] = 0;
      for (i=0;i<8;i++)  XX[56+i] = MDp->count[i];
      MDblock(MDp,XX);
    }
    /* Set flag saying we're done with MD computation */
    MDp->done = 1;
  }
}

/*
** Finish up MD4 computation and return message digest.
*/
void
MD4Final(buf, MD)
unsigned char *buf;
MD4_CTX *MD;
{
  int i, j;
  unsigned int w;

  MD4Update(MD, NULL, 0);
  for (i = 0; i < 4; ++i) {
    w = MD->buffer[i];
    for (j = 0; j < 4; ++j) {
      *buf++ = w;
      w >>= 8;
    }
  }
}


//#define	BYTE_ORDER			LITTLE_ENDIAN redefine ??


#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if BYTE_ORDER == LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
    |(rol(block->l[i],8)&0x00FF00FF))
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
    ^block->l[(i+2)&15]^block->l[i&15],1))

/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);


/* Hash a single 512-bit block. This is the core of the algorithm. */

#if _HTTP_OVER_SSL_ == 1
int SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
#else
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
#endif
{
u_int32_t a, b, c, d, e;
typedef union {
    unsigned char c[64];
    u_int32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1];  /* use array to appear as a pointer */
    memcpy(block, buffer, 64);
#else
    /* The following had better never be used because it causes the
     * pointer-to-const buffer to be cast into a pointer to non-const.
     * And the result is written through.  I threw a "const" in, hoping
     * this will cause a diagnostic.
     */
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
#endif
    /* Copy context->state[] to working vars */
    a = state[0];
    b = state[1];
    c = state[2];
    d = state[3];
    e = state[4];
    /* 4 rounds of 20 operations each. Loop unrolled. */
    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
    /* Add the working vars back into context.state[] */
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
    state[4] += e;
    /* Wipe variables */
    a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
    memset(block, '\0', sizeof(block));
#endif

    #if _HTTP_OVER_SSL_ == 1    
    return 1;
    #endif
}

/* SHA1Init - Initialize new context */
#if _HTTP_OVER_SSL_ == 1
int SHA1Init(SHA1_CTX* context)
#else
void SHA1Init(SHA1_CTX* context)
#endif
{
    /* SHA1 initialization constants */
    context->state[0] = 0x67452301;
    context->state[1] = 0xEFCDAB89;
    context->state[2] = 0x98BADCFE;
    context->state[3] = 0x10325476;
    context->state[4] = 0xC3D2E1F0;
    context->count[0] = context->count[1] = 0;
    
    #if _HTTP_OVER_SSL_ == 1
    return 1;
    #endif
}

/* Run your data through this. */
#if _HTTP_OVER_SSL_ == 1
int SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
#else
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
#endif
{
u_int32_t i;
u_int32_t j;

    j = context->count[0];
    if ((context->count[0] += len << 3) < j)
    context->count[1]++;
    context->count[1] += (len>>29);
    j = (j >> 3) & 63;
    if ((j + len) > 63) {
        memcpy(&context->buffer[j], data, (i = 64-j));
        SHA1Transform(context->state, context->buffer);
        for ( ; i + 63 < len; i += 64) {
            SHA1Transform(context->state, &data[i]);
        }
        j = 0;
    }
    else i = 0;
    memcpy(&context->buffer[j], &data[i], len - i);

    #if _HTTP_OVER_SSL_ == 1
    return 1;
    #endif
}

/* Add padding and return the message digest. */
#if _HTTP_OVER_SSL_ == 1
int SHA1Final(unsigned char digest[20], SHA1_CTX* context)
#else
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
#endif
{
unsigned i;
unsigned char finalcount[8];
unsigned char c;

#if 0   /* untested "improvement" by DHR */
    /* Convert context->count to a sequence of bytes
     * in finalcount.  Second element first, but
     * big-endian order within element.
     * But we do it all backwards.
     */
    unsigned char *fcp = &finalcount[8];

    for (i = 0; i < 2; i++)
    {
    u_int32_t t = context->count[i];
    int j;

    for (j = 0; j < 4; t >>= 8, j++)
        *--fcp = (unsigned char) t
    }
#else
    for (i = 0; i < 8; i++) {
        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
    }
#endif
    c = 0200;
    SHA1Update(context, &c, 1);
    while ((context->count[0] & 504) != 448) {
    c = 0000;
        SHA1Update(context, &c, 1);
    }
    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
    for (i = 0; i < 20; i++) {
        digest[i] = (unsigned char)
         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
    }
    /* Wipe variables */
    memset(context, '\0', sizeof(*context));
    memset(&finalcount, '\0', sizeof(finalcount));
    
    #if _HTTP_OVER_SSL_ == 1
    return 1;
    #endif
}


static u_char Get7Bits(u_char *input, int startBit)
{
    register unsigned int   word;

    word  = (unsigned)input[startBit / 8] << 8;
    word |= (unsigned)input[startBit / 8 + 1];

    word >>= 15 - (startBit % 8 + 7);

    return word & 0xFE;
}


static void MakeKey(u_char *key, u_char *des_key)
{
    des_key[0] = Get7Bits(key,  0);
    des_key[1] = Get7Bits(key,  7);
    des_key[2] = Get7Bits(key, 14);
    des_key[3] = Get7Bits(key, 21);
    des_key[4] = Get7Bits(key, 28);
    des_key[5] = Get7Bits(key, 35);
    des_key[6] = Get7Bits(key, 42);
    des_key[7] = Get7Bits(key, 49);

#ifndef USE_CRYPT
    des_set_odd_parity((des_cblock *)des_key);
#endif

#if 0
    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
#endif
}


static void
DesEncrypt(u_char *clear, u_char *key, u_char cipher[8])
{
    des_cblock      des_key;
    des_key_schedule    key_schedule;

    MakeKey(key, des_key);

#if _IXP
    mp_des_set_key(&des_key, key_schedule);
#else
    des_set_key(&des_key, key_schedule);
#endif

#if 0
    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
#endif

#if _IXP
	mp_des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
#else
    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
#endif

#if 0
    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
#endif
}



void
ChallengeResponse(u_char *challenge,
          u_char PasswordHash[MD4_SIGNATURE_SIZE],
          u_char response[24])
{
    char    ZPasswordHash[21] = {0};
    
    memcpy(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE);

#if 0
    dbglog("ChallengeResponse - ZPasswordHash %.*B",
       sizeof(ZPasswordHash), ZPasswordHash);
#endif

    DesEncrypt(challenge, (unsigned char *)ZPasswordHash +  0, &response[0]);
    DesEncrypt(challenge, (unsigned char *)ZPasswordHash +  7, &response[8]);
    DesEncrypt(challenge, (unsigned char *)ZPasswordHash + 14, &response[16]);

#if 0
    dbglog("ChallengeResponse - response %.24B", response);
#endif
}

static void
NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
{
#ifdef __NetBSD__
    /* NetBSD uses the libc md4 routines which take bytes instead of bits */
    int         mdlen = secret_len;
#else
    int         mdlen = secret_len * 8;
#endif
    MD4_CTX     md4Context;

    MD4Init(&md4Context);
    MD4Update(&md4Context, (u_char*)secret, mdlen);
    MD4Final(hash, &md4Context);

}

/*
 * Convert the ASCII version of the password to Unicode.
 * This implicitly supports 8-bit ISO8859/1 characters.
 * This gives us the little-endian representation, which
 * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
 * is machine-dependent.)
 */
static void
ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
{
    int i;

    memset(unicode, 0, ascii_len * 2);
    for (i = 0; i < ascii_len; i++)
    unicode[i * 2] = (u_char) ascii[i];
}



static void
ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
          char *username, u_char Challenge[8])
    
{
    SHA1_CTX    sha1Context;
    u_char  sha1Hash[SHA1_SIGNATURE_SIZE];
    char    *user;

    /* remove domain from "domain\username" */
    if ((user = strrchr(username, '\\')) != NULL)
    ++user;
    else
    user = username;

    SHA1Init(&sha1Context);
    SHA1Update(&sha1Context, PeerChallenge, 16);
    SHA1Update(&sha1Context, rchallenge, 16);
    SHA1Update(&sha1Context, (u_char*)user, strlen(user));
    SHA1Final(sha1Hash, &sha1Context);

    memcpy(Challenge, sha1Hash, 8);
}

void
ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
       char *secret, int secret_len, u_char NTResponse[24])
{
    u_char  unicodePassword[MAX_NT_PASSWORD * 2];
    u_char  PasswordHash[MD4_SIGNATURE_SIZE];
    u_char  Challenge[8];

    ChallengeHash(PeerChallenge, (u_char*)rchallenge, username, Challenge);

    /* Hash the Unicode version of the secret (== password). */
    ascii2unicode(secret, secret_len, unicodePassword);
    NTPasswordHash((char*)unicodePassword, secret_len * 2, PasswordHash);

    ChallengeResponse((unsigned char *)Challenge, (unsigned char *)PasswordHash, (unsigned char *)NTResponse);
}


/****************************************end of ChapMS2_NT()****************************************************/

//***********************************************************************************************************************************

// This is from section 10.1 of the TTLS RFC.
char *implicit_challenge(struct generic_eap_data *thisint)
{
    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return NULL;

    return (char *) tls_crypt_gen_keyblock(thisint, TTLS_CHALLENGE, TTLS_CHALLENGE_SIZE);
}

void ChapMS2_NT(char *rchallenge, unsigned char PeerChallenge[16], char *username, char *secret, int secret_len, unsigned char NTResponse[24]);

void GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
			char *UserName, char *Password, char *Response, 
			int nthash)
{
    if (!xsup_assert((AuthenticatorChallenge != NULL),"AuthenticatorChallenge != NULL", FALSE)) return;

    if (!xsup_assert((PeerChallenge != NULL), "PeerChallenge != NULL", FALSE)) return;

    if (!xsup_assert((UserName != NULL), "UserName != NULL", FALSE)) return;

    if (!xsup_assert((Password != NULL), "Password != NULL", FALSE)) return;

    if (!xsup_assert((Response != NULL), "Response != NULL", FALSE)) return;


    ChapMS2_NT(AuthenticatorChallenge, (unsigned char *)PeerChallenge, UserName, Password, strlen(Password), (unsigned char *)Response);
  
//    debug_printf(DEBUG_AUTHTYPES, "PeerChallenge : ");
//    WIMAX_DUMP_BUFFER(0, (uint8_t *) PeerChallenge, 8);
//    debug_printf(DEBUG_AUTHTYPES, "AuthenticatorChallenge : ");
//    WIMAX_DUMP_BUFFER(0, (uint8_t *) AuthenticatorChallenge, 8);
    debug_printf(1, "Username : %s\n",UserName);
    debug_printf(1, "Password : %s\n",Password);

//    debug_printf(DEBUG_AUTHTYPES, "Response : ");
//    WIMAX_DUMP_BUFFER(0, (uint8_t *) Response, 24);
}


/* This function written by Danielle Brevi  */
int tls_crypt_decrypt(  struct generic_eap_data *thisint, uint8_t *in_data, 
		                int in_size, uint8_t *out_data, int *out_size)
{
    struct tls_vars *mytls_vars;
    int rc = 0;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((in_data != NULL), "in_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((out_data != NULL), "out_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((out_size != NULL), "out_size != NULL", FALSE)) return XEMALLOC;

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    if (BIO_reset(mytls_vars->ssl_in) <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt.c, BIO_reset(mytls_vars->ssl_in) failed.\n");
        tls_funcs_process_error();

        return XETLSCRYPTFAIL;
    }

    rc=BIO_write(mytls_vars->ssl_in, in_data, in_size);

    if (BIO_reset(mytls_vars->ssl_out) <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt.c, BIO_reset(mytls_vars->ssl_out) failed.\n");
        tls_funcs_process_error();

        return XETLSCRYPTFAIL;
    }

    rc=SSL_read(mytls_vars->ssl, out_data, 1000);
    if (rc <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt.c, SSL_read(mytls_vars->ssl, out_data, 1000) failed.\n");
        tls_funcs_process_error();

        return XETLSCRYPTFAIL;
    }

    *out_size = rc;

    return XENONE;
}

int tls_crypt_encrypt_nolen(struct generic_eap_data *thisint, uint8_t *in_data,
			                int in_size, uint8_t *out_data, int *out_size)
{
    struct tls_vars *mytls_vars;
    int rc = 0;
    uint8_t *p = NULL;
    int to_send_size = 0;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((in_data != NULL), "in_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((out_data != NULL), "out_data != NULL", FALSE)) return XEMALLOC;

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    /* We need to modify this, to read more when there is more to be returned. */
    p = (uint8_t *)malloc(1000);
    if (p == NULL)
    {
        debug_printf(DEBUG_NORMAL, "Error with malloc of \"p\" in tls_crypt_encrypt().\n");
        return XEMALLOC;
    }

    memset(p, 0, 1000);
  
    if (BIO_reset(mytls_vars->ssl_in) <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt (nolen), BIO_reset failed in encrypt!\n");
        tls_funcs_process_error();
        return -1;
    }

    if (BIO_reset(mytls_vars->ssl_out) <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt (nolen), BIO_reset (2) failed in encrypt!\n");
        tls_funcs_process_error();

        if (p != NULL)
	    {
	        free(p);
	        p = NULL;
	    }

        return -1;
    }

    rc=SSL_write(mytls_vars->ssl, in_data, in_size);
    if (rc <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt (nolen), SSL_write failed in encrypt!\n");
        tls_funcs_process_error();
    }

    rc = BIO_read(mytls_vars->ssl_out, p, 1000);   // Allow largest possible read.
    if (rc <= 0)
    {
        debug_printf(DEBUG_NORMAL, "In tls_crypt (nolen), BIO_read failed in encrypt!\n");
        tls_funcs_process_error();

        if (p != NULL)
	    {
	        free(p);
	        p = NULL;
	    }

        return -1;
    }

    to_send_size = rc;

    out_data[0] = 0x00;  // No more to send.
    memcpy(&out_data[1], p, to_send_size);

    *out_size = to_send_size+1;
    if(p)
    {
        free(p);
        p = NULL;
    }
    return XENONE;
}


#if 0
void build_avp( uint32_t avp_value, uint32_t avp_vendor, uint64_t avp_flags, 
	            uint8_t *in_value, uint64_t in_value_len, uint8_t *out_value, 
	            int *out_size)
#else
void build_avp( uint32_t avp_value, uint32_t avp_vendor, uint32_t avp_flags, 
	            uint8_t *in_value, uint32_t in_value_len, uint8_t *out_value, 
	            int *out_size)
#endif
{
    int avp_padded;
    uint32_t avp_vendor_stuff;
    uint32_t avp_code;
    uint32_t bitmask_avp_len;

    if (!xsup_assert((out_size != NULL), "out_size != NULL", FALSE)) return;

    *out_size = 0;

    if (!xsup_assert((in_value != NULL), "in_value != NULL", FALSE)) return;

    if (!xsup_assert((out_value != NULL), "out_value != NULL", FALSE)) return;

    avp_code = htonl(avp_value);
    avp_vendor_stuff = htonl(avp_vendor);

    if (avp_vendor != 0) 
    {
        in_value_len = in_value_len +4;
    }

    if ((in_value_len % 4) != 0)
    {
        avp_padded = (in_value_len + (4 - (in_value_len % 4)));
    } else {
        avp_padded = in_value_len;
    }
    bitmask_avp_len = htonl((avp_flags << 24) + in_value_len + 8);

    bzero(out_value, avp_padded+12);
    memcpy(&out_value[0], &avp_code, 4);
    memcpy(&out_value[4], &bitmask_avp_len, 4);
    if (avp_vendor != 0)
    {
        memcpy(&out_value[8], &avp_vendor_stuff, 4);
        memcpy(&out_value[12], in_value, in_value_len);
        *out_size = avp_padded+8;
    } else {
        memcpy(&out_value[8], in_value, in_value_len);
        *out_size = avp_padded+8;
    }
}


/**************************************************************
 *
 *  Do an MS-CHAPv2 authentication.  indata, and insize are not used
 * in this function.  (As this is only a one-way conversation.)
 *
 **************************************************************/
void ttls_do_mschapv2(struct generic_eap_data *thisint, char *indata, 
		      int insize, char *out_data, int *out_size)
{
    uint8_t mschap_challenge[16], mschap_answer[50];
    uint8_t mschap_result[24];
    char *username = NULL, *password = NULL, *challenge = NULL;
    int avp_offset, avp_out_size, username_size, id;
    struct config_mschapv2 *phase2data;
    struct config_eap_ttls *outerdata;
    struct config_ttls_phase2 *userdata;

#ifdef HAVE_TNC
    struct config_network *net;
#endif

    if (!xsup_assert((out_size != NULL), "out_size != NULL", FALSE)) return;

    *out_size =0;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return;

    if (!xsup_assert((thisint->eap_conf_data != NULL), "thisint->eap_conf_data != NULL", FALSE)) return;

    outerdata = (struct config_eap_ttls *)thisint->eap_conf_data;

    if (!outerdata->phase2)
    {
        debug_printf(DEBUG_NORMAL, "Invalid phase 2 data.\n");
        return;
    }

    userdata = (struct config_ttls_phase2 *)outerdata->phase2;

    while ((userdata != NULL) && (userdata->phase2_type != TTLS_PHASE2_MSCHAPV2))
    {
        userdata = userdata->next;
    }


    if (!userdata->phase2_data)
    {
        debug_printf(DEBUG_NORMAL, "Invalid phase 2 config in MS-CHAPv2!\n");
        return;
    }

    phase2data = (struct config_mschapv2 *)userdata->phase2_data;

    // Check that we have a password.
    if ((phase2data->password == NULL) && (thisint->tempPwd == NULL))
    {
        debug_printf(DEBUG_AUTHTYPES, "Phase 2 doesn't appear to have a password.  Requesting one!\n");
        thisint->need_password = 1;
        thisint->eaptype = strdup("EAP-TTLS Phase 2 (MS-CHAPv2)");
        thisint->eapchallenge = NULL;
        *out_size = 0;
        return;
    }

    if ((phase2data->password == NULL) && (thisint->tempPwd != NULL))
    {
        phase2data->password = thisint->tempPwd;
        thisint->tempPwd = NULL;
    }

    if (phase2data->username == NULL)
    {
        username = thisint->identity;
    } else {
        username = phase2data->username;
    }

    if (username == NULL)
    {
        debug_printf(DEBUG_NORMAL, "Invalid phase 2 username.  (You may need to populate the phase 2 username field.)\n");
        return;
    }

    username_size = strlen(username);

    // Send the Username AVP
    build_avp(USER_NAME_AVP, 0, MANDITORY_FLAG, (uint8_t *) username, username_size, (uint8_t *) out_data, &avp_out_size);

    avp_offset = avp_out_size;

	WIMAX_PRINT(LOG_INFO, "Calculating implicit challenge");
    challenge = implicit_challenge(thisint);

    if (challenge == NULL)
    {
        debug_printf(DEBUG_NORMAL, "Invalid implicit challenge in MS-CHAPv2!\n");
        return;
    }

    memcpy(&mschap_challenge, challenge, 16);
    id = challenge[16];

    // Send the MS-CHAP AVP
    build_avp(MS_CHAP_CHALLENGE, MS_VENDOR_ATTR, (MANDITORY_FLAG | VENDOR_FLAG), (uint8_t *) &mschap_challenge, 16, (uint8_t *) &out_data[avp_offset], &avp_out_size);

    avp_offset+=avp_out_size;

    bzero(&mschap_answer, 50);  // Clear it out.
    memcpy(&mschap_answer, &mschap_challenge, 16);

    // The first 24 bytes should be left as 0s.
    password = phase2data->password;    // Get our password.

    GenerateNTResponse((char *)&mschap_challenge, (char *)&mschap_challenge, username, password, (char *)&mschap_result, 0);

    mschap_answer[0] = id;
    mschap_answer[1] = 0;
    memcpy(&mschap_answer[2], &mschap_challenge, 16);
    memcpy(&mschap_answer[26], &mschap_result, 24);

    build_avp(MS_CHAP2_RESPONSE, MS_VENDOR_ATTR, (MANDITORY_FLAG | VENDOR_FLAG), (uint8_t *) &mschap_answer, 50, (uint8_t *) &out_data[avp_offset], &avp_out_size);
    avp_offset+=avp_out_size;
    *out_size = avp_offset;
	WIMAX_PRINT(LOG_INFO, "------> MS CHAP V2 RESPONSE      [%d0 ms]", TickTime);
#ifdef HAVE_TNC
    net = config_get_network_config();

    if (TEST_FLAG(net->flags, CONFIG_NET_USE_TNC))
    {
        ttls_tnc_start((uint8_t *)out_data, (size_t*)out_size);
    }
#endif
}


void ttls_do_bogus(struct generic_eap_data *thisint, char *indata, int insize,
		   char *out_data, int *out_size)
{
    debug_printf(DEBUG_NORMAL, "Attempting to call an undefined Phase 2!\n");
}



struct phase2_handler {
    char *phase2name;
    void (*phase2handler)(struct generic_eap_data *, char *, int, char *, int *);
    ttls_phase2_type phase2type;
};

struct phase2_handler phase2types[] = {
  {"UNDEFINED", ttls_do_bogus, TTLS_PHASE2_UNDEFINED},
#if 0
  {"PAP", ttls_do_pap, TTLS_PHASE2_PAP},
  {"CHAP", ttls_do_chap, TTLS_PHASE2_CHAP},
  {"MSCHAP", ttls_do_mschap, TTLS_PHASE2_MSCHAP},
#endif
  {"MSCHAPV2", ttls_do_mschapv2, TTLS_PHASE2_MSCHAPV2},
#if 0
  {"EAP_MD5", ttls_do_eap_md5, TTLS_PHASE2_EAP_MD5},
#endif
  {NULL, ttls_do_bogus, -1}
};


static char decr_data[1550];  //fix_me
int ttls_do_phase2(struct generic_eap_data *thisint, char *in, int in_size, char *out, int *out_size)
{
    int toencsize, i, decrsize = 0;
    char *toencout;
    struct config_eap_ttls *userdata;
    struct config_ttls_phase2 *phase2data;

    if (!xsup_assert((out_size != NULL), "out_size != NULL", FALSE)) return XEMALLOC;

    *out_size = 0;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_conf_data != NULL), "thisint->eap_conf_data != NULL", FALSE)) return XEMALLOC;

 //   debug_printf(DEBUG_AUTHTYPES, "Encrypted Inner (%d) : \n", in_size);
 //   WIMAX_DUMP_BUFFER(0, (uint8_t *) in, in_size);

    userdata = (struct config_eap_ttls *)thisint->eap_conf_data;

    if (!userdata->phase2)
    {
        debug_printf(DEBUG_NORMAL, "Invalid userdata in ttls_do_phase2()!\n");
        return XEGENERROR;
    }

    phase2data = (struct config_ttls_phase2 *)userdata->phase2;

    toencout = (char *)malloc(1550);
    if (toencout == NULL)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't allocate memory needed for encryption!\n");
        return XEMALLOC;
    }

    // This is a hack. :-(  It is needed for TTLS-MS-CHAPv2.
    // XXX Fix better!
    // A better fix would be to figure out how to have OpenSSL tell us how much
    // of the packet it processed, so we can move our offset pointer to the end
    // of the data that has been used.  This would result in a NULL packet
    // being passed in for the first part, and the encrypted packet being
    // passed in the second part.  This would allow us to process the packets
    // "correctly" inside of the specific phase 2 handler.
    if ((in_size > 0) && (in[0] != 0x14))
    {
        // We have something to decrypt!
        tls_crypt_decrypt(thisint, (uint8_t *) in, in_size, (uint8_t *) decr_data, &decrsize);

//        debug_printf(DEBUG_AUTHTYPES, "Decrypted Inner (%d) : \n", in_size);
//        WIMAX_DUMP_BUFFER(0, (uint8_t *) decr_data, decrsize);

#ifdef HAVE_TNC
        // See if we have any Integrity Messages from the IMV to
        // pass to our IMC
        toencsize = 0;
        ttls_tnc_process((uint8_t*)decr_data, decrsize, (uint8_t*)toencout, (size_t*)&toencsize);
      
        if (toencsize)
	    goto encrypt;
#endif

        if ((decr_data[0] == 0x00) && (userdata->phase2_type != TTLS_PHASE2_EAP_MD5))
	    {
//	        debug_printf(DEBUG_AUTHTYPES, "(Hack) Acking for second inner phase packet!\n");
	        out[0] = 0x00;  // ACK
	        *out_size = 1;
	        return XENONE;
	    }
    }

    toencsize = 1550;

    // We need to see what phase 2 method we should use.
    i = 0;

    while ((phase2types[i].phase2type != -1) && (userdata->phase2_type != phase2types[i].phase2type))
    {
      i++;
    }

    if (phase2types[i].phase2type > 0)
    {
        debug_printf(DEBUG_AUTHTYPES, "Doing Phase 2 %s!\n", phase2types[i].phase2name);
        (*phase2types[i].phase2handler)(thisint, decr_data, decrsize, toencout, &toencsize);
    } else {
        debug_printf(DEBUG_NORMAL, "ERROR!  : No phase 2 TTLS method was defined!\n");
        toencsize = 0;
    }

   // ifdef this so that it doesn't cause compiler warnings when building
   // without TNC.
#ifdef HAVE_TNC
 encrypt:
#endif
    if (toencsize == 0)
    {
        *out_size = 0;
        free(toencout);
        return XENONE;
    }

//    debug_printf(DEBUG_AUTHTYPES, "To encrypt :\n");
//    WIMAX_DUMP_BUFFER(0, (unsigned char *)toencout, toencsize);

    tls_crypt_encrypt_nolen(thisint, (uint8_t *) toencout, toencsize, (uint8_t *) out, out_size);
    free(toencout);

//    debug_printf(DEBUG_AUTHTYPES, "Returning from (TTLS) do_phase2 : \n");
//    WIMAX_DUMP_BUFFER(0, (uint8_t *) out, *out_size);
    return XENONE;
}

void ttls_phase2_failed(struct generic_eap_data *thisint)
{
    struct config_eap_ttls *userdata;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return;

    if (!xsup_assert((thisint->eap_conf_data != NULL), "thisint->eap_conf_data != NULL", FALSE)) return;

    userdata = (struct config_eap_ttls *)thisint->eap_conf_data;

    if (!userdata->phase2)
    {
        debug_printf(DEBUG_NORMAL, "Invalid userdata in ttls_phase2_failed()!\n");
        return;
    }

    if (userdata->phase2_type == TTLS_PHASE2_EAP_MD5)
    {
        if (eap_clear_active_method(userdata->phase2_eap_data) != XENONE)
	    {
	        debug_printf(DEBUG_NORMAL, "Couldn't clean up EAP-MD5 from TTLS phase 2.\n");
	    }
    }
}

//***********************************************************************************************************************************
int tls_funcs_failed(struct generic_eap_data *thisint)
{
    struct tls_vars *mytls_vars;
    int res = 0;

    debug_printf(DEBUG_NORMAL, "(TLS-FUNCS) Cleaning up (possible after a failure)!\n");

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!thisint->eap_data)
    {
        debug_printf(DEBUG_NORMAL, "Invalid EAP data in tls_funcs_failed()!\n");
        return XEMALLOC;
    }

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    if (mytls_vars->ssl)
    {
        debug_printf(DEBUG_AUTHTYPES, "(EAP-TLS) Calling SSL_shutdown()\n");
        res = SSL_shutdown(mytls_vars->ssl);

        if (res == 0)
	    {
	        /* Need to call it again to complete the shutdown. */
	        res = SSL_shutdown(mytls_vars->ssl);
	  
	        if (res == 0)
	        {
	            debug_printf(DEBUG_AUTHTYPES, "Couldn't shut down SSL connection. We will leak memory!\n");
	        }
	    }
        SSL_free(mytls_vars->ssl);
        mytls_vars->ssl = NULL;
    }

    if (mytls_vars->ctx)
    {
        debug_printf(DEBUG_AUTHTYPES, "(EAP-TLS) Freeing mytls_vars->ctx!\n");
        SSL_CTX_free(mytls_vars->ctx);
        mytls_vars->ctx = NULL;
    }

    if (mytls_vars->sessionkeyconst != NULL)
    {
        debug_printf(DEBUG_AUTHTYPES, "(EAP-TLS) Freeing session key const!\n");
        free(mytls_vars->sessionkeyconst);
        mytls_vars->sessionkeyconst = NULL;
    }

    return XENONE;
}

int tls_funcs_cleanup(struct generic_eap_data *thisint)
{
    int err=XENONE;
    struct tls_vars *mytls_vars;

    debug_printf(DEBUG_NORMAL, "(TLS-FUNCS) Cleaning up!\n");

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL", FALSE)) return XEMALLOC;

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    err = tls_funcs_failed(thisint);

#if 0 //we don't have engine
    if (mytls_vars->engine)
    {
        debug_printf(DEBUG_NORMAL, "Cleaning up OpenSSL Engine\n");
        ENGINE_finish(mytls_vars->engine);
        mytls_vars->engine = NULL;
        debug_printf(DEBUG_NORMAL, "Cleaning up OpenSSL Engine internal ressources\n");
        ENGINE_cleanup();
    }
#endif
    return err;
}

static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
    char buf[256];
    X509 *err_cert;
    int err, depth;

    if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE)) return XEMALLOC;

    err_cert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    depth = X509_STORE_CTX_get_error_depth(ctx);
    X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);

    debug_printf(DEBUG_AUTHTYPES, "     --- SSL_verify : depth %d\n", depth);

     if (!preverify_ok)
    {
        debug_printf(DEBUG_AUTHTYPES, "     --- SSL_verify error : num=%d:%s:depth=%d:%s\n",
		    err, X509_verify_cert_error_string(err), depth, buf);

        if (err == 26) preverify_ok = 1;
    }

    return preverify_ok;
}


int tls_funcs_build_new_session(struct tls_vars *mytls_vars)
{
	int res;
    if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE)) return XEMALLOC;

    if (mytls_vars->ssl)
    {
        SSL_free(mytls_vars->ssl);
        mytls_vars->ssl = NULL;
    }
    
    mytls_vars->ssl = SSL_new(mytls_vars->ctx);

    if (!mytls_vars->ssl)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't create SSL object!\n");
        tls_funcs_process_error();
      
        return XETLSSTARTFAIL;
    }

	mytls_vars->ssl->EapOverUSB = 1;
	switch(cipher_id)
	{
	case 0:
		res = SSL_set_cipher_list(mytls_vars->ssl, SSL3_TXT_RSA_RC4_128_MD5);
        debug_printf(DEBUG_NORMAL, "cipher suite: SSL3_TXT_RSA_RC4_128_MD5");
		break;

	case 1:
		res = SSL_set_cipher_list(mytls_vars->ssl, TLS1_TXT_RSA_WITH_AES_256_SHA );
        debug_printf(DEBUG_NORMAL, "cipher suite: TLS1_TXT_RSA_WITH_AES_256_SHA");
		break;

	case 2:
		res = SSL_set_cipher_list(mytls_vars->ssl, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA);
        debug_printf(DEBUG_NORMAL, "cipher suite: TLS1_TXT_DHE_RSA_WITH_AES_256_SHA");
		break;

	default:
        debug_printf(DEBUG_NORMAL, "Try to set unsupport cipher suite");
		break;
	}
	

    return XENONE;
}
  
int tls_funcs_start(struct tls_vars *mytls_vars)
{
    SSL_SESSION *sess = NULL;
    unsigned long err;
    int counter, resval = XENONE;

    if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE)) return XEMALLOC;

    mytls_vars->resuming = 0;

    if (!mytls_vars->ssl)
    {
        resval = tls_funcs_build_new_session(mytls_vars);
        if (resval != XENONE) 
	    {
	        debug_printf(DEBUG_NORMAL, "Error building a new session!\n");
	        return resval;
	    }
		SSL_set_quiet_shutdown(mytls_vars->ssl, 1);  //fchien try

    } else {
        // We already established a connection, so we probably we need to
        // resume the session.
        if (mytls_vars->resume == RES_YES)
	    {
	        sess = SSL_get_session(mytls_vars->ssl);
	        if (!sess)
	        {
	            debug_printf(DEBUG_AUTHTYPES, "Couldn't get session information! We won't try to resume this session!\n");
	            mytls_vars->resuming = 0;

	            // Clear the old session data.
	            SSL_free(mytls_vars->ssl);

	            // Set up a new session.
	            resval = tls_funcs_build_new_session(mytls_vars);
	            if (resval != XENONE) return resval;
	        } else {
	            debug_printf(DEBUG_AUTHTYPES, "Got session information, trying to resume session!\n");
	            mytls_vars->resuming = 1;

	            // We don't want to send an alert to the other end..  So do a 
	            // quiet shutdown.  This violates the TLS standard, but it is 
	            // needed to avoid confusing the other end of the connection 
	            // when we want to do a reconnect!
	            SSL_set_quiet_shutdown(mytls_vars->ssl, 1);
	      
	            // Now, close off our old session.
	            err = 0;
	            counter = 0;

	            SSL_shutdown(mytls_vars->ssl);

	            while ((err == 0) && (counter < 60))
		        {
		            err = SSL_shutdown(mytls_vars->ssl);
		            if (err == 0)
		            {
		                //DrayDelay(Unit_ms(10));;
		                process_events_by_mask(10, 0);
		                counter++;
		            }
		        }

	            if (err < 0)
		        {
		            debug_printf(DEBUG_NORMAL, "Error trying to shut down SSL context data.\n");
		            tls_funcs_process_error();
		        }
	        }
	    }
    }//if (!mytls_vars->ssl)

    mytls_vars->ssl_in = BIO_new(BIO_s_mem());
    if (!mytls_vars->ssl_in)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't create ssl_in!\n");
        tls_funcs_process_error();
        return XETLSSTARTFAIL;
    }

    if (BIO_reset(mytls_vars->ssl_in) < 1)
    {
        tls_funcs_process_error();
    }

    mytls_vars->ssl_out = BIO_new(BIO_s_mem());
    if (!mytls_vars->ssl_out)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't create ssl_out!\n");
        tls_funcs_process_error();
        return XETLSSTARTFAIL;
    }

    if (BIO_reset(mytls_vars->ssl_out) < 0)
    {
        tls_funcs_process_error();
    }

    SSL_set_bio(mytls_vars->ssl, mytls_vars->ssl_in, mytls_vars->ssl_out);

    if (sess != NULL)
    {
        // If we have session information, we need to use it to resume the 
        // session.
        debug_printf(DEBUG_AUTHTYPES, "Attempting to resume session...\n");
        if (SSL_set_session(mytls_vars->ssl, sess) <= 0)
	    {
	        debug_printf(DEBUG_NORMAL, "There was an error attempting to resume the session!\n");
	        tls_funcs_process_error();
	    }
    }

    // Set this to SSL_VERIFY_NONE if we don't want to do anything with a failed
    // verification.

    SSL_set_verify(mytls_vars->ssl, mytls_vars->verify_mode, ssl_verify_callback);

    return XENONE;
}

int tls_funcs_parse(struct generic_eap_data *thisint, uint8_t *indata, 
		    int insize, char *outdata, int *outsize, int chunksize)
{
    int rc;
    BUF_MEM *retData;
    struct tls_vars *mytls_vars;
    char *retVal;
    uint32_t length;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    // indata can be NULL (at the start of a TLS conversation.

    if (!xsup_assert((outdata != NULL), "outdata != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((outsize != NULL), "outsize != NULL", FALSE)) return XEMALLOC;

    if (insize > 1520)
    {
        debug_printf(DEBUG_NORMAL, "Packet passed in to tls_funcs_parse() is too big! Ignoring!\n");
        return XEBADPACKETSIZE;
    }

    if ((chunksize == 0) || (chunksize > 1398))
    {
        chunksize = 1398;
    }

    if (thisint->eap_data == NULL) 
    {
        debug_printf(DEBUG_NORMAL, "(TLS) eap_data has been destroyed, or not allocated!\n");
        return XEMALLOC;
    }
    mytls_vars = (struct tls_vars *)thisint->eap_data;

    if (!mytls_vars)
    {
        debug_printf(DEBUG_NORMAL, "mytls_vars == NULL!\n");
        return XEMALLOC;
    }

    if (mytls_vars->tlsoutsize==0) 
    {
        if (indata != NULL)
	    {
	        if (BIO_write(mytls_vars->ssl_in, indata, insize) < 2)
	        {

				debug_printf(DEBUG_NORMAL, "BIO_write() mytls_vars->ssl_in ERROR!!!!\n");
	            tls_funcs_process_error();
	        }
	    } 

        if (BIO_reset(mytls_vars->ssl_out) < 0)
	    {
			debug_printf(DEBUG_NORMAL, "BIO_reset() mytls_vars->ssl_out ERROR!!!!\n");
	        tls_funcs_process_error();
	    }

        if (mytls_vars->ssl == NULL) 
	    {
	        debug_printf(DEBUG_NORMAL, "SSL context is NULL!!!!\n");
	        return XETLSNOCTX;
	    }

        rc = SSL_connect(mytls_vars->ssl);
        if (rc < 0)
	    {
	        tls_funcs_process_error();
	    }

        BIO_get_mem_ptr(mytls_vars->ssl_out, &retData);
      
        mytls_vars->tlsoutdata = retData->data;
        mytls_vars->tlsoutsize = retData->length;
//		WIMAX_DUMP_BUFFER(0, (unsigned char*)retData->data, retData->length);
    }

    if (mytls_vars->tlsoutsize == 0) 
    {
        return XTLSNEEDDATA;
    }

    if ((mytls_vars->tlsoutsize - mytls_vars->tlsoutptr)>chunksize)
    {
        // Return a maximum sized chunk.
      
        if (mytls_vars->tlsoutptr == 0)  // This is our first chunk, include
	    {                              // the length.
	        outdata[0] = EAPTLS_LENGTH_MORE;  // We will have a length value, and more.
	        length = htonl(mytls_vars->tlsoutsize);
	        memcpy(&outdata[1], &length, 4);
	        retVal = &outdata[5];
	        *outsize = chunksize+5; // To account for length.
	    } else {
	        outdata[0] = EAPTLS_MORE_FRAGS;
	        retVal = &outdata[1];
	        *outsize = chunksize+1;
	    }

        memcpy(retVal, &mytls_vars->tlsoutdata[mytls_vars->tlsoutptr], chunksize);
        mytls_vars->tlsoutptr += chunksize;

    } else {
        // Return what is left.

        if (mytls_vars->tlsoutptr == 0)  // This is our first chunk, include
	    {                              // the length.
	        outdata[0] = EAPTLS_LENGTH_INCL;  // We will have a length value.
	        length = htonl(mytls_vars->tlsoutsize);
	        memcpy(&outdata[1], &length, 4);
	        retVal = &outdata[5];
	        *outsize = (mytls_vars->tlsoutsize - mytls_vars->tlsoutptr)+5;
	    } else {
	        outdata[0] = EAPTLS_FINAL;
	        retVal = &outdata[1];
	        *outsize = (mytls_vars->tlsoutsize - mytls_vars->tlsoutptr)+1;
	    }

        memcpy(retVal, &mytls_vars->tlsoutdata[mytls_vars->tlsoutptr], *outsize);
      
        // Clean out the data chunk.
        mytls_vars->tlsoutptr = 0;
        mytls_vars->tlsoutsize = 0;
    }

    return XENONE;
}

#if 0

/************************************************************************
 *
 * Notify the eap method that the attempt has failed.  This should be used
 * for things such as destroying a password that has failed, so it will be
 * requested again.  Or, for resetting a context in the case of TLS based
 * authentication methods.
 *
 ************************************************************************/
int eap_do_fail(struct generic_eap_data *activemethod)
{
    int eapmethod = 0;

    // Make sure that we have something to clear.
    if (activemethod == NULL)
    {
        debug_printf(DEBUG_AUTHTYPES, "There was no method defined for executing a failure!\n");
        return XENONE;
    }

    eapmethod = eap_find_type(activemethod->eapNum);

    if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't find an EAP type handler to notify of the failure!\n");
        return XENONE;
    }

    if (eaphandlers[eapmethod].eap_auth_failed == NULL) 
    {
        debug_printf(DEBUG_AUTHTYPES, "EAP handler didn't have a failure method!\n");
        return XENONE;
    }

    (*eaphandlers[eapmethod].eap_auth_failed)(activemethod);

    return XENONE;
}

char *get_cert_common_name(SSL *ssl_ctx)
{
  char *commonName = NULL;
  X509 *server_cert;

  if (!xsup_assert((ssl_ctx != NULL), "ssl_ctx != NULL", FALSE))
    return NULL;

  // Get our certificate.
  server_cert = SSL_get_peer_certificate(ssl_ctx);

  if (!server_cert) return NULL;

  commonName = (char *)malloc(512);
  if (commonName == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to hold the common name!\n");
      return NULL;
    }

  if (X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
				NID_commonName, commonName, 512) < 0)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't extract common name from server certificate!\n");
      return NULL;
    }

  debug_printf(DEBUG_AUTHTYPES, "Extracted common name of %s\n",commonName);
  return commonName;
}

#endif

int tls_funcs_cn_check(struct tls_vars *mytls_vars)
{
#if 0   //fix_me
    char *cnname = NULL;
    char *temp = NULL;

    if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE)) return XEMALLOC;

    if (mytls_vars->cncheck != NULL)
    {
        cnname = get_cert_common_name(mytls_vars->ssl);

        debug_printf(DEBUG_AUTHTYPES, "Certificate CN : %s\n",cnname);

        // mytls_vars->cncheck == NULL, do nothing.
        debug_printf(DEBUG_AUTHTYPES, "Doing a CN Check!\n");

        if (mytls_vars->cnexact == 1)
	    {
	        debug_printf(DEBUG_AUTHTYPES, "Looking for an exact match!\n");

	        if (cnname != NULL)
	        {
	            if (strcmp(mytls_vars->cncheck, cnname) != 0)
		        {
		            debug_printf(DEBUG_AUTHTYPES, "Certificate CN didn't match!\n");
		            free(cnname);
		            return XEBADCN;
		        } else {
		            debug_printf(DEBUG_AUTHTYPES, "Certificate CN matched!\n");
		        }
	        }
	    } else {
	        debug_printf(DEBUG_AUTHTYPES, "Looking for a relative match!\n");

	        temp = mytls_vars->cncheck;
	        if (cnname != NULL)
	        {
	            if (strstr(cnname, temp) == NULL)
		        {
		            debug_printf(DEBUG_AUTHTYPES, "Certificate CN didn't match!\n");
		            free(cnname);
		            return XEBADCN;
		        } else {
		            debug_printf(DEBUG_AUTHTYPES, "Certificate CN matched!\n");
		        }
	        }
	    }
    }

    if (cnname != NULL)
    {
        free(cnname);
        cnname = NULL;
    }
#endif
    return XENONE;
}

int tls_funcs_build_ack(char *outframe, int *outsize)
{
//    debug_printf(DEBUG_EVERYTHING, "Sending TLS ACK!\n");

    if (!xsup_assert((outframe != NULL), "outframe != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((outsize != NULL), "outsize != NULL", FALSE)) return XEMALLOC;

    outframe[0] = 0x00;
    *outsize = 1;
    return XENONE;
}


/***************************************************
 *
 * Cleanup the active EAP type, and anything else that we set up for using
 * EAP.
 *
 ***************************************************/
void eap_cleanup(struct generic_eap_data **clearmethod)
{
    int searchval;
    struct generic_eap_data *activemethod;

    if ((!clearmethod) || (!(*clearmethod))) 
    {
        debug_printf(DEBUG_AUTHTYPES, "There was no active method in eap_cleanup()!\n");
        return;
    }

    activemethod = *clearmethod;

    debug_printf(DEBUG_AUTHTYPES, "Calling EAP-Cleanup!\n");
    searchval = 0;

    if (activemethod->eapNum != 0)
    {
        searchval = eap_find_type(activemethod->eapNum);

        if (eaphandlers[searchval].eap_auth_type != NO_EAP_AUTH)
	    {
	        (*eaphandlers[searchval].eap_auth_cleanup)(activemethod);
	        activemethod->eapNum = 0;
	    } else {
	        debug_printf(DEBUG_NORMAL, "Couldn't clean up after active EAP type! (Type : %d)\n",activemethod->eapNum);
	        debug_printf(DEBUG_NORMAL, "This shouldn't be possible!  Please report it to the XSupplicant list!\n");
	    }

        if (activemethod->identity != NULL)
	    {
	        free(activemethod->identity);
	        activemethod->identity = NULL;
	    }

        if (*clearmethod != NULL)
	    {
	        free(*clearmethod);
	        *clearmethod = NULL;
	    }
    }
}

/************************************************************************
 *
 * Clear the active EAP type.  This will be called when the EAP type we are
 * using has changed, or we have encountered another event (such as an
 * essid change) that should require a completely new authentication!
 *
 ************************************************************************/
int eap_clear_active_method(struct generic_eap_data *activemethod)
{
    int eapmethod = 0;

    // First, make sure we have something to clean up.
    if (activemethod == NULL)
    {
        debug_printf(DEBUG_AUTHTYPES, "There was nothing to clean up in eap_clear_active_method!\n");
        return XENONE;
    }

    if (activemethod->eapNum == 0)
    {
        debug_printf(DEBUG_NORMAL, "Invalid EAP type %d!\n", activemethod->eapNum);
        return -1;
    }

    if (activemethod->identity)
    {
        free(activemethod->identity);
        activemethod->identity = NULL;
    }

    eapmethod = eap_find_type(activemethod->eapNum);

    (*eaphandlers[eapmethod].eap_auth_cleanup)(activemethod);
    activemethod->eapNum = 0;

    return XENONE;
}

#if 0

// fanny : fixme....why 2910 ssl/t1_enc.c : tls1_P_hash() use this function ??
void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags)
{
	EVP_MD_CTX_set_flags(&ctx->i_ctx, flags);
	EVP_MD_CTX_set_flags(&ctx->o_ctx, flags);
	EVP_MD_CTX_set_flags(&ctx->md_ctx, flags);
}

SSL3_ENC_METHOD TLSv1_enc_data =
{
	tls1_enc,
	tls1_mac,
	tls1_setup_key_block,
	tls1_generate_master_secret,
	tls1_change_cipher_state,
	tls1_final_finish_mac,
	TLS1_FINISH_MAC_LENGTH,
	tls1_cert_verify_mac,
	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
	tls1_alert_code,
};


static SSL_METHOD *tls1_get_method(int ver)
{
	if (ver == TLS1_VERSION)
		return(TLSv1_method());
	else
		return(NULL);
}

int tls1_new(SSL *s)
{
	if (!ssl3_new(s)) return(0);
	s->method->ssl_clear(s);
	return(1);
}

void tls1_free(SSL *s)
{
	ssl3_free(s);
}

void tls1_clear(SSL *s)
{
	ssl3_clear(s);
	s->version=TLS1_VERSION;
}

long tls1_default_timeout(void)
{
	/* 2 hours, the 24 hours mentioned in the TLSv1 spec
	 * is way too long for http, the cache would over fill */
	return(60*60*2);
}

int ssl_undefined_void_function(void)
{
	return(0);
}

// already define in : ssl/ssl_locl.h

IMPLEMENT_tls1_meth_func(TLSv1_method,
			ssl3_accept,
			ssl3_connect,
			tls1_get_method)

#endif

/* TLS PRF from rfc2246 pages 11-12 */
int
tls_funcs_PRF(uint8_t *secret, int secret_len, uint8_t *label, int label_len, 
	     uint8_t *seed, int seed_len, uint8_t *output, int outlen)
{
  int retVal = 0;
  int L_S1, L_S2;
  uint8_t *S1, *S2;
  uint8_t *P_MD5_buf, *P_SHA1_buf;
  uint8_t *P_seed;
  int P_seed_len;
  uint8_t A_MD5[MD5_DIGEST_LENGTH];
  uint8_t A_SHA1[SHA_DIGEST_LENGTH];
  int MD5_iterations, SHA1_iterations;
  int i, hashed_len;
  const EVP_MD *hash;
  HMAC_CTX ctx;
  if (!xsup_assert((secret != NULL), "secret != NULL", FALSE))
    return XEMALLOC;

  if (!xsup_assert((label != NULL), "label != NULL", FALSE))
    return XEMALLOC;

  if (!xsup_assert((seed != NULL), "seed != NULL", FALSE))
    return XEMALLOC;

  if (!xsup_assert((output != NULL), "output != NULL", FALSE))
    return XEMALLOC;

  /* determine the length of "half" the secret */
  if (secret_len % 2 == 0) {
    L_S1 = secret_len / 2;
  }
  else {
    L_S1 = secret_len / 2 + 1;
  }
  L_S2 = L_S1;
  S1 = secret; /* first L_S1 bytes of secret */
  S2 = secret + secret_len - L_S2;  /* last L_S2 bytes of secret */
  MD5_iterations = outlen / MD5_DIGEST_LENGTH;
  /* if there is anything left over, iterate 1 more time */
  MD5_iterations = outlen % MD5_DIGEST_LENGTH == 0 ? 
    MD5_iterations : MD5_iterations + 1;
  SHA1_iterations = outlen / SHA_DIGEST_LENGTH;
  SHA1_iterations = outlen % SHA_DIGEST_LENGTH == 0 ?
    SHA1_iterations : SHA1_iterations + 1;
  P_seed_len = label_len + seed_len;
  P_seed = (uint8_t *)malloc(sizeof(uint8_t) * P_seed_len);
  if (P_seed == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Error with malloc of P_seed in tls_funcs_PRF().\n");
      return XEMALLOC;
    }

  memcpy(P_seed, label, label_len);
  memcpy(P_seed+label_len, seed, seed_len);
  P_MD5_buf = (uint8_t *)malloc(sizeof(uint8_t) * 
			       MD5_iterations  * MD5_DIGEST_LENGTH);
  if (P_MD5_buf == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Error with malloc of P_MD5_buf in tls_funcs_PRF().\n");
      free(P_seed);
      P_seed = NULL;
      return XEMALLOC;
    }

  P_SHA1_buf = (uint8_t *)malloc(sizeof(uint8_t) *
				SHA1_iterations * SHA_DIGEST_LENGTH);
  if (P_SHA1_buf == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Error with malloc of P_SHA1_buf in tls_funcs_PRF().\n");
      free(P_seed);
      P_seed = NULL;
      free(P_MD5_buf);
      P_MD5_buf = NULL;
      return XEMALLOC;
    }

  /* P_MD5 */
  hash = EVP_md5();
  /* Initialize A_MD5 */
  HMAC(hash, S1, L_S1, P_seed, P_seed_len, A_MD5, (u_int *) &hashed_len);

  for (i = 0; i < MD5_iterations; i++) {
    HMAC_Init(&ctx, S1, L_S1, hash);
    HMAC_Update(&ctx, A_MD5, MD5_DIGEST_LENGTH);
    HMAC_Update(&ctx, P_seed, P_seed_len);
    HMAC_Final(&ctx, P_MD5_buf + i*(MD5_DIGEST_LENGTH), (u_int *) &hashed_len);
    HMAC_cleanup(&ctx);
    HMAC(hash, S1, L_S1, A_MD5, MD5_DIGEST_LENGTH,
	 A_MD5, (u_int *) &hashed_len);
  }
    

  /* do P_SHA1 */
  hash = EVP_sha1();
  /* Initialize A_SHA1 */
  HMAC(hash, S2, L_S2, P_seed, P_seed_len, A_SHA1, (u_int *) &hashed_len);

  for (i = 0; i < SHA1_iterations; i++) {
    HMAC_Init(&ctx, S2, L_S2, hash);
    HMAC_Update(&ctx, A_SHA1, SHA_DIGEST_LENGTH);
    HMAC_Update(&ctx, P_seed, P_seed_len);
    HMAC_Final(&ctx, P_SHA1_buf + i*(SHA_DIGEST_LENGTH), (u_int *) &hashed_len);
    HMAC_cleanup(&ctx);
    HMAC(hash, S2, L_S2, A_SHA1, SHA_DIGEST_LENGTH,
	 A_SHA1, (u_int *) &hashed_len);
  }
  /* XOR Them for the answer */
  for (i = 0; i < outlen; i++) {
    *(output + i) = P_MD5_buf[i] ^ P_SHA1_buf[i];
  }
  if (P_seed)
    {free(P_seed); P_seed = NULL;}
  if (P_MD5_buf) 
    {free(P_MD5_buf); P_MD5_buf = NULL;}
  if (P_SHA1_buf) 
    {free(P_SHA1_buf); P_SHA1_buf = NULL;}
  return retVal;
}


/*************************************************
 *
 * Ask the EAP method to give us keying material.
 *
 *************************************************/
int eap_get_keying_material(struct interface_data *inf)
{
    int eapmethod = 0;

    if (!xsup_assert((inf != NULL), "thisint != NULL", FALSE)) return XEMALLOC;


    if (inf->activemethod == NULL)
    {
        debug_printf(DEBUG_AUTHTYPES, "The EAP type doesn't seem to exist anymore?!\n");
        return XENONE;
    }

    eapmethod = eap_find_type(inf->activemethod->eapNum);

    if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't find an EAP type handler to clean up from!\n");
        debug_printf(DEBUG_NORMAL, "We will probably leak memory!\n");
        return XENONE;
    }

    (*eaphandlers[eapmethod].eap_auth_get_keys)(inf);

 //   thisint->statemachine->PMK = (char *) thisint->keyingMaterial;
 //   debug_printf(DEBUG_INT, "PMK Keys (%d) :\n", inf->keyingLength);
 //   WIMAX_DUMP_BUFFER(0, (uint8_t *) inf->keyingMaterial, inf->keyingLength);

    return XENONE;
}

#define TLS_SESSION_KEY_SIZE        128

uint8_t *tls_crypt_gen_keyblock(struct generic_eap_data *thisint, char *sesskey,
			      int sesskeylen)
{
    uint8_t seed[SSL3_RANDOM_SIZE*2];
    uint8_t *p = seed;
    struct tls_vars *mytls_vars;
    uint8_t *retblock;

//    debug_printf(DEBUG_EVERYTHING, "Generating key block!\n");

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return NULL;

    if (!xsup_assert((sesskey != NULL), "sesskey != NULL", FALSE)) return NULL;

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    if (!mytls_vars->ssl)
    {
        debug_printf(DEBUG_NORMAL, "No valid SSL context found!\n");
        return NULL;
    }

//    debug_printf(DEBUG_EVERYTHING, "Using session key const of : %s\n", sesskey);

    retblock = (uint8_t *)malloc(TLS_SESSION_KEY_SIZE);
    if (!retblock) return NULL;

    memcpy(p, mytls_vars->ssl->s3->client_random, SSL3_RANDOM_SIZE);
    p+= SSL3_RANDOM_SIZE;
    memcpy(p, mytls_vars->ssl->s3->server_random, SSL3_RANDOM_SIZE);
    tls_funcs_PRF(  SSL_get_session(mytls_vars->ssl)->master_key, 
		            SSL_get_session(mytls_vars->ssl)->master_key_length,
		            (uint8_t *) sesskey, sesskeylen, seed, 
		            SSL3_RANDOM_SIZE * 2, retblock, 
		            TLS_SESSION_KEY_SIZE);

    return retblock;
}

char *tls_funcs_gen_keyblock(struct generic_eap_data *thisint)
{
    struct tls_vars *mydata;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return NULL;

    mydata = (struct tls_vars *)thisint->eap_data;

    if (!xsup_assert((mydata != NULL), "mydata != NULL", FALSE)) return NULL;

    return (char *)tls_crypt_gen_keyblock(thisint, mydata->sessionkeyconst,	mydata->sessionkeylen);
}


/***************************************************
 *
 * Look through the EAP array, and see if we can find the index to the
 * EAP method in question.
 *
 ***************************************************/
int eap_find_type(int eap_type)
{
    int eapmethod;

    xsup_assert((eap_type >= 0), "eap_type >= 0", TRUE);

    // Determine which authenticator in our array is the right one.
    eapmethod = 0;

    while ((eaphandlers[eapmethod].eap_auth_type != NO_EAP_AUTH) &&
	        (eaphandlers[eapmethod].eap_auth_type != eap_type))
    {
        eapmethod++;
    }
     
    if ((eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH) && (eap_type > 3))
    {
        debug_printf(DEBUG_NORMAL, "No EAP Type Handler found for EAP Type %d!\n", eap_type);
    }
  
    return eapmethod;
}

int eapttls_setup(struct generic_eap_data * thisint)
{
  struct tls_vars *mytls_vars;
  struct config_eap_ttls *userdata;

  if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

  userdata = (struct config_eap_ttls *)thisint->eap_conf_data;

  if (userdata == NULL)
  {
      debug_printf(DEBUG_NORMAL, "EAP-TTLS setup was passed NULL userdata!  We"
		   " cannot continue with this attempt at authentication!\n");
      return XENOUSERDATA;
  }

  // First, set up the structure to hold all of our instance specific
  // variables.
  thisint->eap_data = (char *)malloc(sizeof(struct tls_vars));
  if (thisint->eap_data == NULL)
  {
      debug_printf(DEBUG_NORMAL, "Unable to allocate memory for thisint->eapdata in eapttls_setup()!\n");
      return XEMALLOC;
  }

  mytls_vars = (struct tls_vars *)thisint->eap_data;
  bzero(mytls_vars, sizeof(struct tls_vars));

  // Set our variables to NULL.
  mytls_vars->ctx = NULL;
  mytls_vars->ssl = NULL;
  mytls_vars->ssl_in = NULL;
  mytls_vars->ssl_out = NULL;
  mytls_vars->tlsoutdata = NULL;
  mytls_vars->tlsoutsize = 0;
  mytls_vars->tlsoutptr = 0;
  mytls_vars->cncheck = userdata->cncheck;
  mytls_vars->cnexact = userdata->cnexact;
  mytls_vars->phase = 1;
  mytls_vars->resume = userdata->session_resume;
  mytls_vars->quickResponse = TRUE;
  mytls_vars->cert_loaded = FALSE;
  mytls_vars->verify_mode = SSL_VERIFY_NONE;

  mytls_vars->sessionkeyconst = (char *)malloc(TTLS_SESSION_KEY_CONST_SIZE+1);
  if (mytls_vars->sessionkeyconst == NULL) return XEMALLOC;

  bzero(mytls_vars->sessionkeyconst, TTLS_SESSION_KEY_CONST_SIZE+1);
  strncpy(mytls_vars->sessionkeyconst, TTLS_SESSION_KEY_CONST,
	  TTLS_SESSION_KEY_CONST_SIZE);

  mytls_vars->sessionkeylen = TTLS_SESSION_KEY_CONST_SIZE;

//  debug_printf(DEBUG_EVERYTHING, "(EAP-TTLS) Initialized.\n");
  
  if (tls_funcs_init(thisint) != XENONE) 
  {
      debug_printf(DEBUG_NORMAL, "Couldn't initialize OpenSSL!\n");
      return XETLSINIT;
  }


  return XENONE;
}


int tls_funcs_init(struct generic_eap_data *thisint)
{
    struct tls_vars *mytls_vars;
    struct config_eap_ttls *userdata;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XETLSINIT;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL", FALSE)) return XETLSINIT;

    if (!xsup_assert((thisint->eap_conf_data != NULL), "thisint->eap_conf_data != NULL", FALSE)) return XETLSINIT;

    mytls_vars = (struct tls_vars *)thisint->eap_data;
    userdata = (struct config_eap_ttls *)thisint->eap_conf_data;

    if (mytls_vars->ctx != NULL)
    {
        SSL_CTX_free(mytls_vars->ctx);
        mytls_vars->ctx = NULL;
        debug_printf(DEBUG_NORMAL, "mytls_vars->ctx != NULL!!!\n");
    }

    mytls_vars->ctx = SSL_CTX_new(TLSv1_method());
    if (mytls_vars->ctx == NULL)
    {
         debug_printf(DEBUG_NORMAL, "Couldn't initialize OpenSSL TLS library!\n");
         tls_funcs_process_error();
         return XETLSINIT;
    }
    
	mytls_vars->ctx->EapOverUSB = 1;

    return XENONE;
}

int eapttls_process(struct generic_eap_data *thisint, uint8_t *dataoffs, int insize, uint8_t *outframe, int *outsize)
{
    struct config_eap_ttls *userdata;
    struct tls_vars *mytls_vars;
    int result = XENONE;
    int retVal;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_conf_data != NULL), "thisint->eap_conf_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((outframe != NULL), "outframe != NULL", FALSE)) return XEMALLOC;

    userdata = (struct config_eap_ttls *)thisint->eap_conf_data;
    mytls_vars = (struct tls_vars *)thisint->eap_data;


    // Make sure we have a valid packet to process.
    if (dataoffs == NULL) return XENONE;
  
    result=tls_funcs_decode_packet(thisint, (char *) dataoffs, insize, (char *) outframe, outsize,
				                   (phase2_call)ttls_do_phase2, userdata->chunk_size);

    if (result != 0)
    {
        return result;
    }
    return XENONE; //*outsize;
}


int eapttls_get_keys(struct interface_data *inf)
{

    if (!xsup_assert((inf != NULL), "inf != NULL", FALSE)) return XEMALLOC;

    if (inf->keyingMaterial != NULL)
    {
        free(inf->keyingMaterial);
    }
  
    inf->keyingMaterial = (uint8_t *) tls_funcs_gen_keyblock(inf->activemethod);
    inf->keyingLength = TLS_SESSION_KEY_SIZE;

    if (inf->keyingMaterial == NULL) return -1;

    return 0;
}

int eapttls_cleanup(struct generic_eap_data *thisint)
{
    struct tls_vars *mytls_vars;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL",  FALSE)) return XEMALLOC;

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    // Call ttls_phase2_failed first.
    ttls_phase2_failed(thisint);

    tls_funcs_cleanup(thisint);

    if (mytls_vars != NULL)
    {
        free(mytls_vars);
        mytls_vars = NULL;
    }

    debug_printf(DEBUG_EVERYTHING, "(EAP-TTLS) Cleaned up.\n");
    return XENONE;
}

int eapttls_failed(struct generic_eap_data *thisint)
{
    struct tls_vars *mytls_vars;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((thisint->eap_data != NULL), "thisint->eap_data != NULL", FALSE)) return XEMALLOC;

    // Call ttls_phase2_failed first.
    ttls_phase2_failed(thisint);

    mytls_vars = (struct tls_vars *)thisint->eap_data;
    tls_funcs_failed(thisint);

    debug_printf(DEBUG_EVERYTHING, "(EAP-TTLS) Failed. Resetting.\n");
    return XENONE;
}


//only support EAP-TTLS right now
struct eap_type_handler eaphandlers[] = {
#if 0
  {EAP_TYPE_MD5, "EAP_MD5", eapmd5_setup, eapmd5_process, eapmd5_get_keys,
   eapmd5_failed, eapmd5_cleanup},
  {EAP_TYPE_TLS, "EAP_TLS", eaptls_setup, eaptls_process, eaptls_get_keys,
   eaptls_failed, eaptls_cleanup},
#endif //0
  {EAP_TYPE_TTLS, "EAP_TTLS", eapttls_setup, eapttls_process, eapttls_get_keys,
   eapttls_failed, eapttls_cleanup},
#if 0
  {EAP_TYPE_MSCHAPV2, "EAP_MSCHAPV2", eapmschapv2_setup, eapmschapv2_process, 
   eapmschapv2_get_keys, eapmschapv2_failed, eapmschapv2_cleanup},
  {EAP_TYPE_PEAP, "EAP_PEAP", eappeap_setup, eappeap_process, eappeap_get_keys,
   eappeap_failed, eappeap_cleanup},
  {EAP_TYPE_LEAP, "EAP_LEAP", eapleap_setup, eapleap_process, eapleap_get_keys,
   eapleap_failed, eapleap_cleanup},
  {EAP_TYPE_SIM, "EAP_SIM", eapsim_setup, eapsim_process, eapsim_get_keys, 
   eapsim_failed, eapsim_cleanup},
  {EAP_TYPE_AKA, "EAP_AKA", eapaka_setup, eapaka_process, eapaka_get_keys,
   eapaka_failed, eapaka_cleanup},
  {EAP_TYPE_OTP, "EAP_OTP", eapotp_setup, eapotp_process, eapotp_get_keys,
   NULL, eapotp_cleanup},
  {EAP_TYPE_GTC, "EAP_GTC", eapotp_setup, eapotp_process, eapotp_get_keys,
   NULL, eapotp_cleanup},
  {EAP_TYPE_TNC, "EAP_TNC", eaptnc_setup, eaptnc_process, NULL,
   eaptnc_failed, eaptnc_cleanup},
#endif //0
  {NO_EAP_AUTH, 0, 0, 0, 0, 0, 0}
};


/****************************************
 *
 * Return our current network data structure.
 *
 ****************************************/

int tls_funcs_decode_packet(struct generic_eap_data *thisint, char *inframe, 
			    int insize, char *outframe, int *outsize,
			    phase2_call dophase2, int chunksize)
{
    unsigned long err;
    int rtnVal = XENONE, tlsindex;
    char *tlsptr;
    struct tls_vars *mytls_vars;

    if (!xsup_assert((thisint != NULL), "thisint != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((inframe != NULL), "inframe != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((outframe != NULL), "outframe != NULL", FALSE)) return XEMALLOC;

    if (!xsup_assert((outsize != NULL), "outsize != NULL", FALSE)) return XEMALLOC;

    if (insize > 1520)
    {
          debug_printf(DEBUG_NORMAL, "Packet size too big in tls_funcs_decode_packet()!  Ignoring!\n");
         return XEBADPACKETSIZE;
    }

//    debug_printf(DEBUG_AUTHTYPES, "Packet in (%d) :\n", insize);
//    WIMAX_DUMP_BUFFER(0,  (uint8_t *) inframe, insize);

    // First, make sure we don't have any errors.
    err = ERR_get_error();
    if (err != 0)
    {
        debug_printf(DEBUG_NORMAL, "OpenSSL Error -- %s\n", ERR_error_string(err, NULL));
    }

    mytls_vars = (struct tls_vars *)thisint->eap_data;

    if (mytls_vars == NULL)
    {
        debug_printf(DEBUG_NORMAL, "EAP data is invalid in tls_funcs_decode_packet()!\n");
        return XEMALLOC;
    }

    *outsize = 0;

    // Set up a pointer to the start of the data.
    tlsindex = 1;
    tlsptr = &inframe[tlsindex];

    rtnVal = XENONE;

    // The first byte should tell us what to do.
    switch ((uint8_t)inframe[0])
    {
        case EAPTLS_START:
	        debug_printf(1, "<------ TTLS-START      [%d0 ms]", TickTime);
            if (tls_funcs_start(mytls_vars) != XENONE)
	        {
	            debug_printf(DEBUG_NORMAL, "There was an error starting the TLS handshake!\n");
	        }

            if (mytls_vars->ssl == NULL)
	        {
	            debug_printf(DEBUG_NORMAL, "The SSL handle is invalid in tls_funcs_decode_packet()!\n");
	            return XETLSNOCTX;
	        }

            rtnVal = tls_funcs_parse(thisint, NULL, 0, outframe, outsize, chunksize);
            if (rtnVal < 0)
	        {
	            debug_printf(DEBUG_NORMAL, "Failed to generate TLS data!\n");
	        }
            break;

        case EAPTLS_LENGTH_MORE:
        case EAPTLS_LENGTH_INCL:
            // Skip the four octets that contain the length.  OpenSSL knows when
            // we are done.
            tlsptr+=4;
            tlsindex+=4;

            // DON'T BREAK HERE!  We want to do the next case!

        case EAPTLS_MORE_FRAGS:
        case EAPTLS_ACK:
                if (!mytls_vars) printf("\r\nmytls_vars is hosed!\n");
                if (!mytls_vars->ssl) printf("\r\nmytls_vars->ssl is hosed!\n");
                if ((SSL_is_init_finished(mytls_vars->ssl) != 0) && (dophase2 != NULL))
	            {
	                // Handle the phase 2 piece.  We pass in the encrypted piece of
	                // the packet, and let phase 2 deal with it!

	                // But, before we do anything, verify the CN.
	                if (tls_funcs_cn_check(mytls_vars) != XENONE)
	                {
	                    debug_printf(DEBUG_NORMAL, "Failed certificate common name check!\n");
	                    *outsize = 0;
	                    return XEBADCN;
	                }

	                // We are in phase 2, so indicate it.
	                mytls_vars->phase = 2;
	  
	                if ((mytls_vars->resuming != 1) || (mytls_vars->quickResponse != TRUE))
	                {
	                    rtnVal = (*dophase2)(thisint, (uint8_t *) tlsptr, (insize-tlsindex), outframe, outsize);
	                    if (rtnVal != XINNERSUCCESS)
		                {
		                    if (rtnVal != XENONE)
		                    {
		                        debug_printf(DEBUG_NORMAL, "Phase 2 failure!\n");
		                        return XEPHASE2FAILURE;
		                    }
		                }
	                } else {
	                    if (*outsize == 0)
		                {
		                    debug_printf(DEBUG_AUTHTYPES, "Resumed session, ACKing ACK!\n");
		                    tls_funcs_build_ack(outframe, outsize);
		                    rtnVal = XENONE;	
		                }
	                }	  
                } else { //(SSL_is_init_finished(mytls_vars->ssl) != 0) && (dophase2 != NULL)
	                rtnVal = tls_funcs_parse(thisint, (uint8_t *) tlsptr, (insize-tlsindex), outframe, outsize, chunksize);
	                if (rtnVal < 0)
	                {
	                    debug_printf(DEBUG_NORMAL, "Couldn't parse TLS data.\n");
	                }

      	            if ((SSL_is_init_finished(mytls_vars->ssl) != 0) && 
	                        (dophase2 != NULL) && 
	                        (mytls_vars->quickResponse == TRUE))
	                {
	      
	                    if (tls_funcs_cn_check(mytls_vars) != XENONE)
		                {
		                    debug_printf(DEBUG_NORMAL, "Failed certificate common name check!\n");
		                    *outsize = 0;
		                    return XEBADCN;
		                }

	                    // We made it to phase 2.  So, indicate it.
	                    mytls_vars->phase = 2;

	                    if ((mytls_vars->resuming != 1) || (mytls_vars->quickResponse != TRUE))
		                {
		                    if ((*dophase2)(thisint, (uint8_t *) tlsptr, (insize-tlsindex), outframe, outsize) != XENONE)
		                    {
		                        debug_printf(DEBUG_NORMAL, "Phase 2 Failure.\n");
		                        return XEPHASE2FAILURE;
		                    }
		                } else {
		                    if (*outsize == 0)
		                    {
		                        debug_printf(DEBUG_AUTHTYPES, "Resumed session, ACKing ACK!\n");
		                        tls_funcs_build_ack(outframe, outsize);
		                        rtnVal = XENONE;
		                    }
		                }
	                } 
                    else if (rtnVal == XTLSNEEDDATA) //(SSL_is_init_finished(mytls_vars->ssl) != 0) &...
	                {
		                tls_funcs_build_ack(outframe, outsize);
		                rtnVal = XENONE;
	                } 
	            }
                break;

            default:
                debug_printf(DEBUG_NORMAL, "Invalid TLS flags! (%02X)\n",(uint8_t)inframe[0]);
                rtnVal = XETLSBADFLAGS;
        }

        return rtnVal;
}


/************************************************
 *
 * Create/update the active method struct.
 *
 ************************************************/
int eap_create_active_method(   struct generic_eap_data **activemethod,
			                    char *identity, char *tempPwd)
{
    struct generic_eap_data *mymethod;

    if (!xsup_assert((activemethod != NULL), "activemethod != NULL", FALSE)) return XEMALLOC;

    mymethod = *activemethod;

    if (mymethod == NULL)
    {
        *activemethod = (struct generic_eap_data *)malloc(sizeof(struct generic_eap_data));
        mymethod = *activemethod;

        if (mymethod == NULL)
	    {
	        debug_printf(DEBUG_NORMAL, "Couldn't allocate memory in eap_create_active_method()\n");
	        return XEMALLOC;
	    }

        memset(mymethod, 0, sizeof(struct generic_eap_data));

        mymethod->eap_conf_data = NULL;
        mymethod->eap_data = NULL;
   
        mymethod->identity = strdup(identity);
      
        if (mymethod->identity == NULL)
	    {
	        debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to copy identity!\n");
	    } 
    }

    mymethod->tempPwd = tempPwd;

    return XENONE;
}

/************************************************
 *
 * Process an authentication request.  Based on the information in the packet,
 * we call the correct EAP type.  We return an error if it is an EAP type
 * that we don't know.
 *
 ************************************************/
int eap_request_auth(struct interface_data * inf, 
		             char *inframe, int insize, char *outframe, int *eapsize)
{
    struct eap_header *myouteap, *myineap;
    int eapmethod, working_eap_type, eapinsize = 0;
    char *tosendframe;
    int retVal = XENONE;
    struct generic_eap_data *activemethod;

    activemethod = inf->activemethod;
    if (!xsup_assert((outframe != NULL), "outframe != NULL", FALSE)) return XEMALLOC;
    if (!xsup_assert((eapsize != NULL), "eapsize != NULL", FALSE)) return XEMALLOC;

    if (insize < 5)
    {
        // We got a runt EAP frame.  We don't know what to do with it.
        debug_printf(DEBUG_NORMAL, "Can't process EAP request.  Packet must be > 5 bytes, but packet was only %d byte(s).\n", insize);
        return XEMALLOC;
    }

    eapmethod = 0;
    *eapsize = 0;

    myineap = (struct eap_header *)inframe;

	//tosendframe point to EAP type specific payload, i.e. the byte after the EAP Type 
    tosendframe = (char *)&inframe[sizeof(struct eap_header)];
    working_eap_type = myineap->eap_type;
  
    myouteap = (struct eap_header *)outframe;

	//fix_me fix_me better move to other place for flexibility
    activemethod->eap_conf_data = &inf->eap_conf_data;

    // Now, determine which authenticator in our array is the right one by the received packet EAP type
    eapmethod = eap_find_type(working_eap_type);

    if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
        // We don't support the received EAP type, NAK it for our desire EAP type
        debug_printf(DEBUG_NORMAL, "No valid EAP type could be found!\n");
        debug_printf(DEBUG_STATE, "Unsupported EAP type requested. (%d)  Sending NAK!\n",myineap->eap_type);
        myouteap->eap_code = EAP_RESPONSE;
        myouteap->eap_identifier = myineap->eap_identifier;
        myouteap->eap_length = htons(6);
        myouteap->eap_type = EAP_TYPE_NAK;
        outframe[sizeof(struct eap_header)] = EAP_TYPE_TTLS;  //we desire EAP-TTLS 
        *eapsize = 6;
        return XEINVALIDEAP;
    }

    // If we had an EAP type before, and we have changed this time through,
    // make sure we call the cleanup methods.
    if ((activemethod->eapNum > 0) && (activemethod->eapNum != eaphandlers[eapmethod].eap_auth_type))
    {
        debug_printf(DEBUG_AUTHTYPES, "EAP Type Changed!  Cleaning up old type!\n");
        eap_clear_active_method(activemethod);
    }

    // If this is a new EAP type, call the setup method.
    if (activemethod->eapNum == 0)
    {
        if (((*eaphandlers[eapmethod].eap_auth_setup)(activemethod)) != XENONE)
	    {
	        debug_printf(DEBUG_NORMAL, "EAP method failed to set up properly! Calling cleanup routine.\n");
	        eap_cleanup(&activemethod);
	  
	        return XEINVALIDEAP;
	    }
	  
        activemethod->eapNum = eaphandlers[eapmethod].eap_auth_type;

        if (activemethod->eap_data == NULL)
	    {
	        debug_printf(DEBUG_AUTHTYPES, "This EAP type didn't set up any state information!?\n");
	    }
    } 

    activemethod->eapid = myineap->eap_identifier;
    eapinsize = ntohs(myineap->eap_length)-5;


    //call the corresponding handler to process the request packet and get the response packet
    switch ((*eaphandlers[eapmethod].eap_auth_handlers)(activemethod, 
	    			                                    (uint8_t *) tosendframe, eapinsize, 
						                                (uint8_t *) &outframe[sizeof(struct eap_header)], 
						                                eapsize))
	{
	    case XINNERSUCCESS:
	        retVal = XINNERSUCCESS;
	        break;

	    case XTLSNEEDDATA:
	        break;

	    case XENONE:
	        break;

	    default:
	        debug_printf(DEBUG_NORMAL, "Unexpected result was returned from the EAP handler.\n");
	        return XEGENERROR;
	}

    if (*eapsize > 0)
    {
        //we have a response packet, fill EAP header
        *eapsize = *eapsize + (sizeof(struct eap_header));
        myouteap->eap_length = htons(*eapsize);
	    myouteap->eap_code = EAP_RESPONSE;
	    myouteap->eap_identifier = myineap->eap_identifier;
        myouteap->eap_type = activemethod->eapNum;
    } 

    return retVal;
}

/***************************************************
 *
 * Respond to a request Auth.
 *
 ***************************************************/
char eap_response_auth(struct interface_data *inf)
{
    int eapsize, eapolver;

//    debug_printf(DEBUG_STATE, "Building EAPOL-Response-Authentication\n");

    if (!xsup_assert((inf != NULL), "inf != NULL", FALSE)) return XEGENERROR;

    if (eap_create_active_method(&inf->activemethod,
			                     inf->identity,
			                     inf->tempPassword) != 0)
    {
        debug_printf(DEBUG_NORMAL, "Couldn't build active method! Authentication will not happen!\n");
        return XEGENERROR;
    }


    switch (eap_request_auth(  inf,
	                		   (char *) &inf->recvframe[inf->rx_usb_header_len],
			                   inf->recv_size, 
	                		   (char *) &inf->sendframe[inf->tx_usb_header_len], 
			                   &eapsize))
    {
        case XINNERSUCCESS:
            // We got a LEAP success, so we need to tell the state machine to
            // create the keying material.
            break;
      
        case XEINVALIDEAP:
            debug_printf(DEBUG_AUTHTYPES, "Invalid EAP type, or couldn't initialize EAP!\n");
      
            // We failed for some reason, so clear the received buffer length so we don't
            // continue to try to process things.
            inf->recv_size = 0;
            break;
      
        case XEGENERROR:
            inf->recv_size = 0;
            break;
    }
  
    if (eapsize != 0)
    {
        inf->send_size = eapsize + inf->tx_usb_header_len;
        return XENONE;
    }

    debug_printf(DEBUG_INT, "No response frame was built!\n");
    return XENOFRAMES;
}


void eap_process_hints(struct interface_data *inf)
{
    //fix_me
}


/*******************************************
 *
 * Process the EAP piece of the packet, determine what type of EAP packet it is
 * and set state machine variables accordingly.  The variables set will
 * cause the state machine to know what to do next.
 *
 *******************************************/
int eap_process_header(struct interface_data *inf)
{
    struct eap_header *myeap;
    uint8_t *inframe;

    if (!xsup_assert((inf != NULL), "inf != NULL", FALSE)) return XEGENERROR;

    inframe = inf->recvframe;

    myeap = (struct eap_header *)&inframe[inf->rx_usb_header_len];

    switch (myeap->eap_code)
    {
        case EAP_REQUEST:
            switch (myeap->eap_type)
            {
	            case EAP_TYPE_IDENTITY:
	                debug_printf(1, "<------ EAP Request/Identity      [%d0 ms]", TickTime);
	                eap_process_hints(inf);
	                return EAP_REQUEST_ID;
	  
	            case EAP_TYPE_NOTIFY:
	                debug_printf(DEBUG_EVERYTHING, "<------ EAP-Notify      [%d0 ms]", TickTime);
	                return EAP_REQUEST_NOTIFY;
	  
	            default:
//	                debug_printf(DEBUG_EVERYTHING, "Got EAP-Request-Authentication.\n");
	                if (ntohs(myeap->eap_length) <= 4)
	                {
	                    debug_printf(DEBUG_NORMAL, "Got invalid EAP packet, ignoring!\n");
	                } 
                    else 
                    {
	                    return EAP_REQUEST_AUTH;
	                }
            }
            break; //case EAP_REQUEST

       case EAP_RESPONSE:
	        debug_printf(1, "<------ EAP-Response, ignoring      [%d0 ms]", TickTime);
            break;

       case EAP_SUCCESS:
            debug_printf(1, "<------ EAP-Success      [%d0 ms]", TickTime);

            if (inf->activemethod == NULL)
            {
	            debug_printf(DEBUG_NORMAL, "Invalid activemethod after success packet recv!\n");
	            break;
            }

	        debug_printf(DEBUG_NORMAL, "Successfully authenticated\n");

            // And get our keying material
            eap_get_keying_material(inf);

			//send MSK to dongle
			if(inf->send_key_to_dongle)
				inf->send_key_to_dongle(inf->keyingMaterial);
			else
				debug_printf(1, "No send key to dongle method");

			if_up();

            break;

        case EAP_FAILURE:
            debug_printf(1, "<------ EAP-Failure      [%d0 ms]", TickTime);

#if 0
            eap_do_fail(inf->activemethod); 
#else
			usb_eap_disconnect();
#endif     
            break;

    } //switch (myeap->eap_code)

    return XENONE;
}



/************************************************
 *
 * Process an EAP Request ID, and respond with the username information that
 * we have configured.  (If nothing is configured, we should ignore the
 * packet, and just return.  Returning an outsize of 0 means that we are
 * ignoring things.)
 *
 ************************************************/
void eap_request_id(char *identity, int eapid, char *outframe, 
		    int *eapsize)
{
  struct eap_header *myeap;
  char *username_ofs;
  
  if (!xsup_assert((identity != NULL), "identity != NULL", FALSE))
    return;

  if (!xsup_assert((outframe != NULL), "outframe != NULL", FALSE))
    return;

  if (!xsup_assert((eapsize != NULL), "eapsize != NULL", FALSE))
    return;

  myeap = (struct eap_header *)outframe;

  myeap->eap_code = EAP_RESPONSE;
  myeap->eap_identifier = eapid; 

  *eapsize = (strlen(identity)+sizeof(struct eap_header));
  myeap->eap_length = htons(*eapsize);
  myeap->eap_type = EAP_TYPE_IDENTITY;

  username_ofs = (char *)&outframe[sizeof(struct eap_header)];
  strncpy(username_ofs, identity, strlen(identity)+1);
}

/***************************************************
 *
 * Respond to a request ID.
 *
 ***************************************************/
char eap_response_id(struct interface_data *inf)
{
    int eapsize, eapolver;
    struct eap_header *eapdata;
  
//    debug_printf(DEBUG_STATE, "Building EAP-Response-ID!\n");

    if (!xsup_assert((inf != NULL), "inf != NULL", FALSE)) return XEGENERROR;

    // See if we need to prepopulate the ID, fchien: we don't need this, it is used for EAP-AKA/SIM
//    eap_prepopulate_id(inf);

    eapdata = (struct eap_header *)&inf->recvframe[inf->rx_usb_header_len];

    if (inf->identity == NULL)
    {
        debug_printf(DEBUG_NORMAL, "No identity!  Make sure you have an identity value in all of your network profiles!\n");
        return XEGENERROR;
    }

    debug_printf(DEBUG_NORMAL, "------>EAP Response/Identity : %s      [%d0 ms]", inf->identity, TickTime);

    eap_request_id( inf->identity,
		            eapdata->eap_identifier,
		            (char *) &inf->sendframe[inf->tx_usb_header_len], &eapsize);

    inf->send_size = eapsize + inf->tx_usb_header_len;
    return XENONE;
}


/*******************************************
 *
 * We got an EAP-Notify message.  Parse, and display it for now.
 *
 *******************************************/
void eap_do_notify(struct interface_data *inf)
{
    struct eap_header *myeap;
    uint8_t *inframe;
    int insize;

    if (!xsup_assert((inf != NULL), "inf != NULL", FALSE)) return;

    inframe = inf->recvframe;
    insize = inf->recv_size;

    myeap = (struct eap_header *)&inframe[inf->rx_usb_header_len];

    // We need to determine how long the string that we were returned is.
    // So, take the EAP length value, and subtract 5 to account for the EAP
    // header.

    if (ntohs(myeap->eap_length) <= sizeof(struct eap_header))
    {
        debug_printf(DEBUG_NORMAL, "EAP notification message is a runt!\n");
        return;
    }

    inframe[inf->rx_usb_header_len + ntohs(myeap->eap_length)] = 0;
    debug_printf(DEBUG_NORMAL, "EAP Notification : %s\n", &inframe[inf->rx_usb_header_len + sizeof(struct eap_header)]);
    inf->recv_size = 0;             // So we don't process this again.

}

unsigned char pre_eap_id = 0xFF;
/****************************************************
 * Function: Process the EAP/USB packet received
 * Return Value:
 *   0: rsp_urb is sent to USB layer successfully, completion routine will free it
 *      otherwise caller has to free it
 *        
 ****************************************************/
int usb_eap_process(struct interface_data *inf, unsigned char * req_eap_pkt, int req_len, unsigned char* rsp_eap_pkt)
{
    // If ctx is NULL, we have a showstopper!
    xsup_assert((inf != NULL), "inf != NULL", TRUE);

    inf->recvframe = req_eap_pkt;
    inf->recv_size = req_len;
    inf->sendframe = rsp_eap_pkt;
    if (!xsup_assert((inf->recvframe != NULL), "usb_eap_process() gets a NULL rx packet", FALSE)) return -1;
    if (!xsup_assert((inf->recv_size < 2000), "usb_eap_process() gets over_size rx packet", FALSE)) return -1;
    if (!xsup_assert((inf->sendframe != NULL), "usb_eap_process() gets a NULL Tx packet", FALSE)) return -1;

	//DH take 4 sec to compute share secret, server will send duplicate packet, drop it
	if(req_eap_pkt[5] == pre_eap_id && req_eap_pkt[4] < 3 ) return 0;

	pre_eap_id = req_eap_pkt[5];
    switch (eap_process_header(inf)) 
    {
        case EAP_REQUEST_ID:
            if (eap_response_id(inf) == XENONE)
            {
	            // send EAP response packet over USB
				if(inf->send_to_usb)
					return inf->send_to_usb(rsp_eap_pkt, inf->send_size, WIMAX_TX_EAP_PKT);
				else
					debug_printf(DEBUG_NORMAL, "No usb send method");
            }
            break;

        case EAP_REQUEST_AUTH:
            if (eap_response_auth(inf) == XENONE)
            {
	            // send EAP response packet over USB
				if(inf->send_to_usb)
					return inf->send_to_usb(rsp_eap_pkt, inf->send_size, WIMAX_TX_EAP_PKT);
				else
					debug_printf(DEBUG_NORMAL, "No usb send method");
            }
            break;

        case EAP_REQUEST_NOTIFY:
            //display the alert message
            eap_do_notify(inf);
            break;
    }
	//we did not send rsp_eap_pkt to USB stack, free it here. If it is sent to USB statck it will be released in
	//Tx completion routine
    //RelBuffer((char*) rsp_eap_pkt);
    free((char*) rsp_eap_pkt);
    return 0;
}

#endif //EAP_OVER_USB == 1

