/*
 * This file contains some functionally close enough subroutines which
 * have deal with initial and ending phases of the LU 6.2 verb processing.
 *
 * The "rout" subroutine represents the main entry point of the APPC
 * (Advanced Program to Program Communication or in other words LU 6.2)
 * module. This is in fact the first subroutine which has deal with
 * processing of APPC requests.
 * The APPC requests may come from two sources:
 * - from application program via int 68h, or from
 * - remote APPC module via network.
 *
 * CopyRight 1995. Nicholas Poljakov all rights reserved.
 *
 */
#include <dos.h>
#include <malloc.h>
#include <stdlib.h>
#include <rcb.h>
#include <common.h>
#include <attlu.h>
#include <detach.h>
#include <tcb.h>
#include <scb.h>
#include <rpl.h>
#include <nib.h>
#include <mode.h>
#include <tps.h>
#include <partner.h>
#include <repass.h>
#include <stdio.h>
#include <include.h>
#include <string.h>
#include <fcntl.h>				/* @0100 */
#include <process.h>
#include <arcb.h>
#include <rcballoc.h>
#include <crtp.h>
#include <state1.h>

#include <sys\types.h>
#include <sys\stat.h>

int sk_r_wt(void *);
int SendBlock(void *, void *);
int setrc(void *, void *);
int sendhsf(void *);
int sendhs(void *);
int sendbm(void *, void *);
int sendat(void *);
int rtsend(void *);
unsigned long rmfmh5(void *, void *);
int recwait(void *);
int rcvru(void *, void *);
int rcvhs(void *, void *, void *, void *);
int ralloc(void *, void *);
int psrm(int, void *, void *);
int ps_conv(int, void *);
int proterr(void *, unsigned long);
int preptrcv(void *, void *);
int post_rcb(void *);
struct repass *postopen(void *);
int phsrec(void *);
int pfmh5(void *);
int opndst(void *);
int obtsess(void *, unsigned char);
int Lrf_handler(void *);
int get_sess(void *, void *);
int get_attr(void *);
int fsm_error(unsigned char, void *);
int fsm_conv(unsigned char, unsigned char, void *);
int flush (void *);
int dcp(void *);
int dealloc(void *);
int crtp(void *);
int conv(void *);
int chkparm(void *, void *);
int check_end(unsigned int, void *);
int close_acb(void *);
struct rqb *call_appl(void *);
int buffmng(unsigned char, void *, void *, void *, unsigned, unsigned char, unsigned);
unsigned long attltck(void *);
unsigned long attacheck(void *);
int lu_init(void *);
int lu_sdown(void *);
int clt_vb(unsigned int, void *);
int sessi(unsigned int, void *);
int sessd(unsigned int, void *);
int fpost(void *);
int seek_res(void *);
char *cgetmem(int, int);
int sendhsf(void *);
int opndst(void *);
int alloc_rcb(void *, void *);
int allocate(void *);
int clsdst(void *);
unsigned long calltpn(void *, void *);

extern unsigned ProgPrefix;

struct psp {
       struct lucb *lucb_list_ptr; /* указатель на список lucb */
       struct tcb  *tcb_list_ptr ; /* указатель на список tcb  */
       struct rcb  *rcb_list_ptr ; /* указатель на список rcb  */
       struct rcb  *wait_chain;    /* очеpедь ожидающих RCB */
       char    *param;
     } psp_ini = {NULL, NULL, NULL, NULL, NULL};
struct lucb {
       char    lu_id[8];     /* идентификатор локального LU */
       unsigned char rsrv1;
       char    lu_name[8];   /* имя LU */
       unsigned char rsrv2;
       struct  acb *p_acb;
       struct pnlu *pluptr;  /* указатель на
                              * список partner_lu   */
       struct  trp *trp_ptr;    /* указатель на
                                 * transaction_program_list  */
       struct pending_data_list *pdlptr; /* список данных,
                                          * посланных в BIND
                                          * к партнеру */
       struct mode *p_mode; /* List of mode blocks for this LU */
       struct scb *scb_list;
       unsigned char lu_session_limit;  /* максимальное количество
                                    сессий LU-LU для локального LU */
       unsigned char cur_sess; /* current number of sessions*/
       int  max_tps; /* max. number of total tps for this LU */
       int  cur_tps; /* current number of tps */
       int  queue_depth;
       struct tcb  *tcb_list_ptr ; /* указатель на список tcb  */
       struct lucb *next; /* next LUCB */
    } lu6;
struct acb {
 short rsrv1;
 short leng;
 char rsrv2[4];
 unsigned long int iface;
 char rsrv3;
 unsigned macr2:8;
 struct acb *acb_next;
 struct rpl *rpl;
 char rsrv4[10];
 unsigned long int passw;
 unsigned long int uel;
 char rsrv5[3];
 unsigned am:8;          /* 0x60-NTAM           */
 unsigned long int deb;
 unsigned oflgs:8;       /* 0x10-OPEN           */
 unsigned erflg:8;       /* 0x04-ALREADY OPEN   *
                          * 0x14-NOT ENOUGH STORAGE*/
 char rsrv6[22];
 unsigned long int apid;
 char rtn[6];
} acb_ini;

int sw_retry[10];
char dispflag;
struct rcb *wait_rcb;

extern void (_interrupt _far *oldint68)( void );
extern char svarea;
extern char _huge *tsrstack;
char _huge *altstack;
char _huge *altsave;

extern char lupost;
void _far *tp_exit;
char *buff;

/*  Literal pool */

char name_lu6[8] = "LU6****";
/* char name6[8] = "MODE6**";
char name0[8] = "MODE0**";
char name_tp[8] = "TP00001"; */
char tpi[6] = "TPXXX";

            unsigned int code;  /* Verb code */
            unsigned int SaveCode[10];
            unsigned int mask;
            char *s_ptr;    /* Pointer to verb record */
            char *SavePtr[10];
            char *t_ptr;
            int from_appl[10];
            int ss_ptr = 0;
            char *temp;
            struct in_parm {
                             unsigned int  verb_cd;
                             unsigned long verb_ptr;
                            } parm;
            struct repass *p_rep;
            struct rqb *p_rqb;

#define HSrec 0x00ff

void _interrupt _far rout( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
			       unsigned _flags )
{
        /*
         * Map of svarea -
         *        offset : 0 - sp of application programm
         *        offset : 2 - ss of application programm
         *        offset : 4 - sp of "appl" part of PORT
         *        offset : 6 - ss of "appl" part of PORT
         *        offset : 8 - ds of LU module.
         *        offset : 20 - pointer to psp_ini
         */

	    /* Save current stack of application, and set old stack of TSR.
	     * This is for safety since we don't know the state of the
	     * application stack, but we do know the state of our own stack.
	     * Turn off interrupts during the stack switch.
	     */

        FP_SEG( s_ptr ) = _ds;
        FP_OFF( s_ptr ) = _dx;
        _disable();
        code = _ax;
        SaveCode[ss_ptr] = code; /* Save code for retry */
        SavePtr[ss_ptr] = s_ptr;
        _asm
                {
                    mov  ax, seg svarea
                    push es
                    mov  es, ax
                    mov  ax, ds
                    mov  WORD PTR es:svarea[8], ax   ; Save data segment
                    pop  es
                }
        mask = code & 0x00ff;
        if (mask == 0x00ff) { /* from APPL */
            from_appl[ss_ptr] = YES;
	    p_rqb = (struct rqb *)s_ptr;
            if (!(p_rqb ->th.ra.code & 0x7f)) {
             /* Segment */
                s_ptr -= 12;
            }
            _asm
            {
                mov  ax, seg svarea
                mov  es, ax
                mov  WORD PTR es:svarea[4], sp   ; Save current stack
		mov  WORD PTR es:svarea[6], ss
		mov  ax, seg altstack
		mov  es, ax
		mov  sp, WORD PTR es:altstack[0] ; Load LU stack
		mov  ss, WORD PTR es:altstack[2]
            }
        }
        else
                {
                    from_appl[ss_ptr] = No;
                    _asm
                    {
                        mov  ax, seg svarea
                        mov  es, ax
                        mov  WORD PTR es:svarea[0], sp   ; Save current stack
			mov  WORD PTR es:svarea[2], ss
			mov  ax, seg tsrstack
			mov  es, ax
			mov  sp, WORD PTR es:tsrstack[0] ; Load LU stack
			mov  ss, WORD PTR es:tsrstack[2]
                    }
                }

       ss_ptr++;

	    _enable();

        /* Make APPC verb processing */

        /*
         * Init. verb record if request from TP.
         */
        if ((code != POSTOPEN)&&(code != DR)&&
            (code != FMHRCV)&&(code != SESSINI)&&
            (code != CLSSESS)&&(code != CLSSESS)) {
	    p_rep = (struct repass *)s_ptr;
            p_rep -> complete = 0;
            p_rep -> p_rcb = NULL;
            p_rep -> tp_fd = 0;
        }
 Retry :
        switch (code) {
          case LRF :     { /* Local resource failure */
                             Lrf_handler(s_ptr);
                             break;
                         }

          case Attach_lu:
                         {
                             lu_init(s_ptr);
                             break;
                         }
          case Detach_lu:
                         {
                             lu_sdown(s_ptr);
                             break;
                         }
          case TP_STARTED:
          case TP_ENDED:
                         {
                             clt_vb(code, s_ptr);
                             break;
                         }
          case FMHRCV :  /* Record from HS, FMH-5 or FMH-7 header */
                         {
                             /* s_ptr points to RQB */
                             s_ptr = (char *)s_ptr - 12;
                             /* s_ptr points to SEGPRF now */
                             phsrec(s_ptr);
                             break;
                         }
          case SESSINI :
                         {
                             /* s_ptr points to RQB */
                             s_ptr = (char *)s_ptr - 12;
                             /* s_ptr points to SEGPRF now */
                             sessi(code, s_ptr);
                             break;
                         }
          case CLSSESP :
          case CLSSESS :
                         {
                             sessd(code, s_ptr);
                             break;
                         }
          case DR :
                         {
                             if (fpost(s_ptr) == 0) {
                             }
                             break;
                         }
          case CONVERT :
                         {
                             conv(s_ptr);
                             break;
                         }
          case POSTOPEN:
                         {
			     t_ptr = (char *)postopen(s_ptr);
                             temp = t_ptr;
                             if (temp == NULL) {
                               code = -1;
                             }
                             break;
                         }
          case Allocate:
                         {
                           ps_conv(code,s_ptr);
                           break;
                         }
          case Confirm:
          case COnfirmed:
          case Deallocate:
          case Flush:
          case Get_attributes:
          case Post_on_receipt:
          case Prepare_to_receive:
          case Receive_and_wait:
          case Receive_immediate:
          case Request_to_send:
          case Send_data:
          case Send_error:
          case Test:
           {
              if (seek_res(s_ptr) == 0)
                 {
                    /* найден в списке */
                     ps_conv(code, s_ptr);
                 }
              break;
           }
          default : break;
        }
        /* Check if verb processing is complete.
         * If it's true write response to TP FIFO,
         * otherwise place RCB in wait qenue.
         */
        sw_retry[ss_ptr - 1] = No;
        check_end(code, s_ptr);
        if (sw_retry[ss_ptr - 1] == YES) {
             sw_retry[ss_ptr - 1] = No;
             code = SaveCode[ss_ptr - 1];
             s_ptr = SavePtr[ss_ptr - 1];
             goto Retry;
        }

	    /* Restore application stack. */
	    _disable();
        if (from_appl[ss_ptr - 1] == YES) {
            from_appl[ss_ptr - 1] = No;
            _asm
            {
                mov  ax, seg svarea
                mov  es, ax
                mov  sp, WORD PTR es:svarea[4]
                mov  ss, WORD PTR es:svarea[6]
            }
        }
        else
                {
                   _asm
                   {
                       mov  ax, seg svarea
                       mov  es, ax
                       mov  sp, WORD PTR es:svarea[0]
                       mov  ss, WORD PTR es:svarea[2]
                   }
                }
	ss_ptr--;
}
seek_res(s_ptr)
char *s_ptr;
{
  struct com *c;
  struct tcb *t;
  struct rcb *r;
  struct repass *p_rep;
#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */
rtype = INPROC;
strcpy(pname, "seek_rs");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif

  /*
   * Seek LU_ID and TP_ID for this request
   */
  c = (struct com *)s_ptr;
  p_rep = (struct repass *)s_ptr;
  c -> prim_rc = OK;
  c -> sec_rc = 0x00000000;

  t = lu6.tcb_list_ptr;
  if (t == NULL) {
      c -> prim_rc = PARAMETR_CHECK;
      c -> sec_rc = 0xf0040000; /* Incomplete */
      return(-1);
  }
  while (t != NULL) {
      if (memcmp(c -> tp_id, t -> tcb_id, 8) != 0) {
              goto next_tcb;
      }
      break;
      next_tcb:
               t = t -> next;
  }
  if (t == NULL) {
      c -> prim_rc = PARAMETR_CHECK;
      c -> sec_rc = 0x00000001; /* Bad tp_id */
      return(-1);
  }
  r = t -> rcb_list_ptr;
  if (r == NULL) {
      c -> prim_rc = PARAMETR_CHECK;
      c -> sec_rc = 0xf0040000; /* Incomplete */
      return(-1);
  }
  while (r != NULL) {
      if (c -> conv_id != r -> rcb_id) {
         goto next_rcb;
      }
      break;
      next_rcb:
               r = r -> next;
  }
  if (r == NULL) {
      c -> prim_rc = PARAMETR_CHECK;
      c -> sec_rc = BAD_CONV_ID;
      return(-1);
  }
  p_rep -> p_rcb = r;
  return (0);
}

lu_init(s_ptr)
char *s_ptr;
{
    int j,k;
    int t;
    unsigned int addr;
    unsigned int *ind;
    struct attach_lu *a_lu;
    struct plu *p_lu;
    struct plu_mode *p_mode;
    struct pnlu *pr_lu;
    struct mode *p_md;
    struct pnlu *pr_t; /* Temp pointer */
    struct rqb *p_rqb;
    char *p;
    char *pt;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "lu_init");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif

    a_lu = (struct attach_lu *)s_ptr;

#if OS_TYPE == 0 /* MS_DOS */
    if ((p_rqb = (struct rqb *)calloc(1, sizeof(struct rqb))) == NULL) {
         a_lu -> rc = 0xf0030000; /* PORT abended */
	 return 0;
    }
    p_rqb -> th.ra.stcb = APPL_CODE;
    p_rqb -> th.ra.code = p_rqb -> th.ra.code & 0xbf; /* TOP */
    p_rqb -> th.ra.code |= 0x80; /* RQB */
    memcpy(p_rqb->th.ra.wa.area, a_lu -> lu_name, 8);
    p_rqb -> th.ra.rparm.parm.parm1 = 6; /* Attach */
    p = (char *)call_appl(p_rqb);
    free( p_rqb );
    if (p == NULL) {
         a_lu -> rc = INVALID_LU_NAME;
	 return 0;
    }
#endif

    a_lu = (struct attach_lu *)s_ptr;

    /* Set stack for entry from APPL */

    if ((altstack = malloc(2048)) == NULL) {
         a_lu -> rc = 0xf0030000; /* PORT abended */
	 return 0;
    }
    altsave = altstack; /* save alt. stack address */
    _asm
	 {
	    mov  ax, seg altstack
	    mov  es, ax
	    mov  bx, offset altstack
	    mov  ax, word ptr es:[bx]
            add  ax, 2048                   ; new stack pointer
	    mov  word ptr es:[bx], ax
         }

    p = (char *)&lu6;
    memset(p, 0, sizeof(struct lucb));
    psp_ini.lucb_list_ptr = &lu6;
    psp_ini.tcb_list_ptr = NULL;
    psp_ini.rcb_list_ptr = NULL;

    memset(&lu6, 0, sizeof(struct lucb));

    a_lu -> rc = 0; /* OK in return code */
    tp_exit = a_lu -> tp_exit; /* address for TP exit routine */

    /* Initialisation LUCB block */

    pt = &((*a_lu).lu_name);
    memcpy(lu6.lu_name, pt, 8);
/* Set LU identification */
    j = 8 - sizeof(int);
    memcpy(lu6.lu_id, name_lu6, j);
    addr = getpid();
    ind = &(lu6.lu_id[8 - j]);
    *ind = addr; /* LU_ID is set */
    /* And then return it */
    p = &((*a_lu).lu_id);
    memcpy(p, lu6.lu_id, 8);

    lu6.lu_session_limit = a_lu -> lu_s_limit;
    lu6.max_tps = a_lu -> max_tps;
    lu6.cur_tps = 0;
    lu6.queue_depth = a_lu -> queue_depth;

    /* Allocation and initialisation PARTNER_LU block */

    k = a_lu -> lt_plu; /* Total length of partner lu records*/
    p_lu = (char *)a_lu + sizeof(struct attach_lu);
                         /* Sizeof struct "attach_lu" */
    pr_t = NULL;
    while (k > 0) {
        t = sizeof(struct plu);
        p_mode = (char *)p_lu + t;
        /* Allocate memory for partner_lu */
        if ((pr_lu = malloc(sizeof(struct pnlu))) == NULL) {
            a_lu -> rc = 0xf0030000; /* PORT abended */
	    return 0;
        }
        /* Allocate memory for mode block */
        if ((p_md = malloc(sizeof(struct mode))) == NULL) {
            a_lu -> rc = 0xf0030000; /* PORT abended */
	    return 0;
        }
        if (lu6.pluptr == NULL) {
            lu6.pluptr = pr_lu;
        }
        pr_lu -> m_ptr = p_md;
        pr_lu -> sess_limit = a_lu -> lu_s_limit;
	p = (char *)&((*p_lu).plu_name);
	pt = (char *)&((*p_mode).mode_name);

        memcpy(pr_lu -> lu_name, p, 8);
        memcpy(p_md -> name, pt, 8);
        p_md -> session_limit = p_mode -> mmax_neg_slim;
        p_md -> ru_h_size = p_mode -> ru_h_size;
        p_md -> ru_l_size = p_mode -> ru_l_size;
        if (pr_t != NULL) {
           pr_t -> next = pr_lu;    /* Insert in chain */
        }
        pr_lu -> next = NULL;
        pr_lu -> lu_type = p_lu -> plu_a_num; /* LU type */
        p_md -> next = NULL;
        pr_t = pr_lu;
        j = p_lu -> rec_lt;
        k -= j;
	p_lu = (char *)p_lu + p_lu -> rec_lt; /* point to next rec. if it exist */
    }

    lu6.p_acb = &acb_ini;
    open_acb(&acb_ini);
    return (0);
}
int clt_vb(code, s_ptr)
unsigned int code;
char *s_ptr;
{
    struct tp_started *ts;
    struct tp_ended *te;
    struct tcb *t;
    struct tcb *temp;
    unsigned long *tpm;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "clt_vb");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif

    switch (code) {
        case TP_STARTED:
        {
	    ts = (struct tp_started *)s_ptr;
            ts -> rc = OK;

            if (memcmp(ts -> lu_id, lu6.lu_id, 8) != 0) {
               /* Bad lu_id */
               ts -> rc = 0x00000003;
	       return 0;
            }
            if (lu6.cur_tps == lu6.max_tps) {
                ts -> rc = 0x00000243; /* too_many_tps*/
		return 0;
            }
	    if ((t = calloc(1, sizeof(struct tcb))) == NULL) {
                ts -> rc = 0xf0030000; /* PORT abended */
		return 0;
            }
            memset(t, 0, sizeof(struct tcb));
            lu6.cur_tps++;
            if (lu6.tcb_list_ptr == NULL) {
               lu6.tcb_list_ptr = t;
               t -> prev = NULL;
            }
            else
            {
               temp = lu6.tcb_list_ptr;
               while (temp -> next != NULL) {
                   temp = temp -> next;
               }
               temp -> next = t;
               t -> prev = temp;
            }
            t -> next = NULL;
            memcpy(t -> tcb_id, tpi, 4);
            tpm = &((*t).tcb_id[4]);
            *tpm = t;
            t -> rcb_list_ptr = NULL;
            t -> p_lucb = &lu6;
            t -> cur_conv = 0;
#if OS_TYPE == 1
            p = (char *)s_ptr + sizeof(struct tp_started);
            strcpy(t -> tp_name, p);
            if (crtp(t) != 0) {
                ts -> rc = 0xf0030000; /* PORT abended */
                return;
            }
#endif
            memcpy(ts -> tp_id, t -> tcb_id, 8);
            break;
        }
        case TP_ENDED:
        {
	    te = (struct tp_ended *)s_ptr;
            te -> rc = OK;

            temp = lu6.tcb_list_ptr;
            if (temp == NULL) {
                te -> rc = 0xf0040000; /* Incomplete */
		return 0;
            }
            while (temp != NULL) {
                if (memcmp(te -> tp_id, temp -> tcb_id, 8) != 0)
                    goto next_tcb;
                break;
                next_tcb:
                         temp = temp -> next;
            }
            if (temp == NULL) {
                te -> rc = 0x00000001; /* Bad tp_id */
		return 0;
            }
            dcp(temp);
        #if OS_TYPE == 1
            kill(tpst_pid, SIGKILL);
        #endif
        }
     }
}
int lu_sdown(s_ptr)
char *s_ptr;
{
    struct scb *p_scb;
    struct scb *temp_scb;
    struct tcb *p_tcb;
    struct mode *p_mode;
    struct pnlu *p_pnlu;
    struct pnlu *temp_pnlu;
    struct rpl *p_rpl;
    struct nib *p_nib;
    struct detach *d;


#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "lu_sdn");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif

    d = (struct detach *)s_ptr;

    /*
     * Free the TCBs and RCBs.
     */
    p_tcb = lu6.tcb_list_ptr;
    while (p_tcb != NULL) {
        dcp(p_tcb);
        p_tcb = p_tcb -> next;
    }
    /*
     * Close the sessions and free SCBs and RPLs, NIBs.
     */
    p_scb = lu6.scb_list;
    while (p_scb != NULL) {
        p_rpl = p_scb -> p_rpl;
        clsdst(p_rpl);
        p_nib = p_rpl -> p_nib;
        if (p_nib != NULL) {
           free(p_nib);
        }
        free(p_rpl);
        temp_scb = p_scb;
        p_scb = p_scb -> next;
        free(temp_scb);
    }

    /*
     * Free MODE block.
     */
    if ((p_mode = lu6.p_mode) != NULL) {
       free(p_mode);
    }

    /*
     * Free PARTNER_LU blocks
     */
    p_pnlu = lu6.pluptr;
    while (p_pnlu != NULL) {
        temp_pnlu = p_pnlu;
        p_pnlu = p_pnlu -> next;
        free(temp_pnlu);
    }
    if (close_acb(&acb_ini) == -1) {
        d -> rc = 0xf0030000; /* PORT abended */
    }
    else
        d -> rc = OK;
    /*
     * Free input buffer for getverb.
     */
    if (buff != NULL) {
       free(buff);
    }
    if (altsave != NULL) {
       free(altsave);
    }
    freeMCB();
    _disable();
    _dos_setvect( 0x68, oldint68 );
    _dos_freemem( ProgPrefix );  /* free Program memory */
}
int sessi(codex, s_ptr)
unsigned int codex;
struct segprf *s_ptr;  /* pointer to segment */
{
    struct scb *p_scb;
    struct scb *temp_scb;
    struct rpl *p_rpl;
    struct rqb *p_rqb;
    struct pnlu *pr_lu;
    struct rcb *p_rcb;
    struct crtp *p_crtp;
    struct lucb *p_lucb;
    struct tcb *p_tcb;
    struct tcb *temp_tcb;
    struct mode *p_mode;
    char *p;
    struct id {
                 char id_n[4];
                 unsigned long id_id;
              } id_ar;
    struct arcb a_rcb;
    struct rcballoc rcb_a;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "sessi");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif
    p_rqb = (char *)s_ptr + 12;

    /************ 19.12.92 ***************/
    p = (char *)s_ptr + 31;
    temp_scb = lu6.scb_list;
    while (temp_scb != NULL) {
        if (memcmp (temp_scb->lu_name, p, 8) == 0) {
	   p_rpl = temp_scb->p_rpl;
	   p_rpl->arg = p_rqb->th.ra.wa.hh.hscb;
	   return;
	}
        temp_scb = temp_scb->next;
    }
   /****************************************/

    if ((p_rpl = calloc(1, sizeof(struct rpl))) == NULL) {
	return 0;
    }
    p_rpl -> arg = p_rqb -> th.ra.wa.hh.hscb; /* Save CID in RPL*/
    p_rpl -> rsrv3 = 1; /* secondary LU */
    if (lu6.cur_sess == lu6.lu_session_limit) {
        clsdst(p_rpl);
	return 0;
    }
    lu6.cur_sess++;
    if ((p_scb = calloc(1, sizeof(struct scb))) == NULL) {
        clsdst(p_rpl);
	return 0;
    }
    /*
     * Include SCB in SCB list.
     */
    temp_scb = lu6.scb_list;
    if (temp_scb == NULL) {
        lu6.scb_list = p_scb;
        p_scb -> prev = NULL;
    }
    else
            {
                while (temp_scb -> next != NULL) {
                temp_scb = temp_scb -> next;
                }
                temp_scb -> next = p_scb;
                p_scb -> prev = temp_scb;
            }
    /*
     * Initialisation the SCB
     */
    p_scb -> p_rpl = p_rpl;
    p_scb -> p_rcb = NULL;
    p_scb -> next = NULL;
    p_scb -> use = FREE;
    /*
     * Fill scb.lu_name and scb.mode fields
     */
    p = (char *)s_ptr + 31; /* pointer to RU */
    memcpy(p_scb -> lu_name, p, 8);
    /*
     * Try to find this LU name in
     * partner LU list.
     */
    pr_lu = lu6.pluptr;
    while (pr_lu != NULL) {
        if (memcmp(pr_lu -> lu_name, p, 8) == 0) {
           break;
        }
        pr_lu = pr_lu -> next;
    }
    if (pr_lu == NULL) {
     /*  LU name not found */
       clsdst(p_rpl);
       return 0;
    }
    /*
     * Check if it's LU type 0 ?
     */
    if (pr_lu -> lu_type == 0) {

      /*  Yes it's LU type 0 ! */

       p_rpl -> rsrv3 = 0; /* primary LU */
       if ((p_tcb = malloc(sizeof(struct tcb))) == NULL) {
           clsdst(p_rpl);
	   return 0;
       }

      /* Include TCB in tcb chain */

       if (p_lucb -> tcb_list_ptr == NULL) {
          p_lucb -> tcb_list_ptr = p_tcb;
       }
       else
       {
          temp_tcb = p_lucb -> tcb_list_ptr;
          while (temp_tcb -> next != NULL) {
              temp_tcb = temp_tcb -> next;
          }
          temp_tcb -> next = p_tcb;
       }
       p_tcb -> next = NULL;
       p_tcb -> prev = temp_tcb;
       p_tcb -> p_lucb = p_lucb;
       p_tcb -> cur_conv = 1;

       /* Set tcb_id */

       memcpy(id_ar.id_n, "TPxx", 4);
       id_ar.id_id = p_tcb;
       memcpy(p_tcb -> tcb_id, &id_ar, 8);
    /* Fill ALLOCATE_RCB record */

       memcpy(a_rcb.lu_name, p, 8);
       a_rcb.p_tcb = p_tcb;
       p_mode = pr_lu -> m_ptr;
       memcpy(a_rcb.mode_name, p_mode -> name, 8);
    /*
     * ALLOCATE_RCB record is complete.
     */
       codex = ALLOCATE_RCB;
       psrm(codex, &a_rcb, &rcb_a);
       if (rcb_a.rc != OK) {
           clsdst(p_rpl);
	   return 0;
       }
       p_rcb = rcb_a.rcb_ptr;
       p_rcb -> sess_corl = p_rqb -> th.ra.wa.hh.hscb; /* Save CID */
       p_rcb -> conv_state = SEND;  /* Initial state for primary LU */
       p_rpl -> arg = p_rqb -> th.ra.wa.hh.hscb; /* Save CID in RPL*/
       p_rcb -> p_scb = p_scb;
       p_scb -> p_rcb = p_rcb;
       p_scb -> use = IN_USE;
       p_tcb -> rcb_list_ptr = p_rcb;
    /*
     * Fill CREATE_TP structure.
     */
       if ((p_crtp = calloc(1, sizeof(struct crtp))) == NULL) {
           clsdst(p_rpl);
	   return 0;
       }
    /*
     * Initialisation the CREATE_TP record
     */
       p_crtp -> code = 0x0000;   /* data_got exit */
       p_crtp -> sense = 0;
       memcpy(p_crtp -> tp_id, p_tcb -> tcb_id, 8);
       memcpy(p_crtp -> lu_id, p_lucb -> lu_id, 8);
       p_crtp -> conv_id = p_rcb -> rcb_id;
     /*
      * Call exit subroutine for LU type 0.
      */
       calltpn(p_crtp, p_tcb);
    }
}
/*
 * Close down a session, free SCB
 */
int sessd(codex, s_ptr)
unsigned int codex;
struct rqb *s_ptr;
{
    struct scb *p_scb;
    struct scb *temp1_scb;
    struct scb *temp2_scb;
    struct tcb *p_tcb;
    struct rcb *p_rcb;
    struct rcb *temp1_rcb;
    struct rcb *temp2_rcb;
    struct rpl *p_rpl;
    struct nib *p_nib;


#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;           /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "sessd");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif

    /*
     * Seek SCB
     */
    p_scb = lu6.scb_list;
    while (p_scb != NULL) {
        if (memcmp(s_ptr -> th.ra.wa.area, p_scb -> lu_name, 8) != 0) {
            goto N_scb;
        }
        break;
        N_scb:
               p_scb = p_scb -> next;
    }
    if (p_scb == NULL) {
	return 0; /* SCB not found */
    }

    p_rpl = p_scb -> p_rpl;
    p_nib = p_rpl -> p_nib;
    if (codex == CLSSESS) {
        clsdst(p_rpl);
    }
    free(p_rpl);
    free(p_nib);

    if (p_scb -> p_rcb == NULL) {
        goto DelScb;
    }
    p_rcb = p_scb -> p_rcb;
    p_tcb = p_rcb -> p_tcb;
    /*
     * Delete RCB from chain
     */
    if (p_rcb -> prev == NULL) {
        p_tcb -> rcb_list_ptr = NULL;
        goto del_and_exit;
    }
    temp1_rcb = p_rcb -> prev;
    temp2_rcb = p_rcb -> next;
    temp1_rcb -> next = temp2_rcb;
    if (temp2_rcb != NULL) {
	temp2_rcb -> prev = temp1_rcb;
    }

del_and_exit:

    free(p_rcb);
    p_tcb -> cur_conv--;

    /*
     * Delete SCB from chain
     */

DelScb:

    if (p_scb -> prev == NULL) {
        lu6.scb_list = NULL;
        goto SessdExit;
    }
    temp1_scb = p_scb -> prev;
    temp2_scb = p_scb -> next;
    temp1_scb -> next = temp2_scb;
    if (temp2_scb != NULL) {
        temp2_scb -> prev = temp1_scb;
    }

SessdExit:

    free(p_scb);
    lu6.cur_sess--;
    return 0;
}
/*
 * Find and post RCB for received data.
 */
fpost(s_ptr)
/*
 * In case of "receive_data" sptr points to seg. prefix.
 */
struct segprf *s_ptr;
{
    struct scb *p_scb;
    struct rcb *p_rcb;
    struct rqb *p_rqb;
    char *p;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "fpost");
pnum = 1;
drec = s_ptr;
lenr = 200;
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif
    p = (char *)s_ptr;
    p_rqb = (struct rqb *)p;
    s_ptr = (char *)p - 12;
    p = p_rqb -> th.ra.wa.area; /* OLU name */
    p_scb = lu6.scb_list;
    if (p_scb == NULL) {
        return (-1);
    }
    while (p_scb != NULL) {
      /* next is lines for CID seek.
        p_rpl = p_scb -> p_rpl;
        if (p_rpl == NULL)
            goto Next_Scb;
        if (p_rpl -> arg == *cid)
            break;        */
        if (memcmp(p, p_scb -> lu_name, 8) == 0)
            break;

  /* Next_Scb: */
        p_scb = p_scb -> next;
    }
    if (p_scb == NULL) {
        return (-1);
    }
    p_rcb = p_scb -> p_rcb;
    if (p_rcb == NULL) {
        return (-1);
    }
    /* RCB found !!! */
    p_rcb -> hsps = YES;
    /* This indicator must be reset by RECWAIT func. */
    rcvru(p_rcb, s_ptr);
    wait_rcb = p_rcb;
#if OS_TYPE == 0
    post_rcb(p_rcb); /* post rcb if it found in wait qeue */
#endif
    return (0);
}
