#ident "$Id: x25lower.c,v 1.4 1997/09/24 23:13:50 gary Exp $"
/*****************************************************************************
 * Copyright (c) 1988-95 Digi International Inc., All Rights Reserved
 * 
 * This  software  contains  proprietary  and  confidential   information   of
 * Digi International  Inc.   By  accepting  transfer  of this copy, Recipient
 * agrees to retain this software in  confidence,  to  prevent  disclosure  to
 * others,  and  to make no  use of this software other than that for which it
 * was delivered.  This is an unpublished copyright work  Digi   International
 * Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************/

/*******************************************************************
 *
 *  SpiderX25 X25 PLP Driver
 *
 *  Copyright 1991 Spider Systems Limited
 *
 *  X25LOWER.C
 *
 *
 *******************************************************************/

/*
 *	x25lower.c
 *	 /projects/common/PBRAIN/SCCS/pbrainF/dev/sys/x25/0/s.x25lower.c
 *	@(#)x25lower.c	1.26
 *
 *	Last delta created	13:10:16 8/26/92
 *	This file extracted	18:32:58 11/19/92
 *
 */

/* ----------------------------------------------------------------------
                PLP lower interface procedures
   ---------------------------------------------------------------------- */

#define BUFP_T bufp_t

#include "x25_inc.h"
#include "system.h"

#ifndef NULL
#define NULL 0
#endif


extern int     x25lwput();
extern mblk_t *allocb(), *copymsg();


/************************************************************************/
int LL_disreq(lsp)
/************************************************************************/

/*
    Request disconnection of the link identified by fields in ldb lsp.
    If no resource etc. return 0 else 1
*/

struct lsformat FAR *lsp;

{
    register struct ll_msg FAR *msg;
    mblk_t *buf;

    if( 0<= lsp->lref && lsp->lref < x25submax )
    {
	/*
	    Subnetwork ref is OK - is it configured in?
	*/
	if( xsndb[lsp->lref].regok )
	{
	    /*
		Resource available for the disconnect - HIGH PRIORITY?
	    */
	    if( (buf=allocb(sizeof(struct ll_msg),BPRI_HI)) != NULL )
	    {
		buf->b_datap->db_type = M_PROTO;
		buf->b_wptr = buf->b_rptr + sizeof( struct ll_msg );
		msg = (struct ll_msg FAR *) buf->b_rptr;
		msg->ll_type      = LL_CTL;
		msg->ll_command   = LC_DISC;
		msg->ll_connID    = lsp->lconnid;
		msg->ll_yourhandle= lsp->lowhandle;
		x25lwput( xsndb[lsp->lref].wq,buf);
		return(1);
	    }                /* Else no buffer    */
	}                    /* Else not regok   */
    }                        /* Else out of range */

    return(0);               /* ERROR reject the disconnect request */
}


/************************************************************************/
int LL_datareq(lsp,hdr)
/************************************************************************/

/*
    Make data request to the link level identified by the link db 'lsp'.
    Return non-zero if request accepted.
*/

struct lsformat FAR *lsp;
mblk_t *hdr;

{
    register struct ll_msg FAR *msg;

    if( 0<= lsp->lref && lsp->lref < x25submax )
    {

	/*
	    Subnetwork ref is OK - is it configured in?
	*/
	if( xsndb[lsp->lref].regok )
	{
	    if ( xcfg[lsp->cfg_index].trace_active )
		x25_trace(xcfg[lsp->cfg_index].trace_queue,lsp,hdr->b_cont,0);

	    hdr->b_datap->db_type = M_PROTO;
	    hdr->b_wptr = hdr->b_rptr + sizeof( struct ll_msg );
	    msg = (struct ll_msg FAR *) hdr->b_rptr;
	    msg->ll_type      = LL_DAT;
	    msg->ll_command   = LC_DATA;
	    msg->ll_connID    = lsp->lconnid;
	    msg->ll_yourhandle= lsp->lowhandle;
	    x25lwput( xsndb[lsp->lref].wq,hdr);
	    return(1);
	}
    }
    return(0);      /* ERROR reject the request */
}


/************************************************************************/
int LL_conreq(lsp,rema,loca,sclass)
/************************************************************************/

/*
    Request connection of the link identified by fields in ldb lsp.
    If no resource etc. return a non-zero diagnostic code.
*/

struct lsformat FAR *lsp;
struct lsapformat FAR *rema, FAR *loca;
unsigned int sclass;

{
    register struct ll_msgc FAR *msg;
    mblk_t *buf1;

    if( 0<= lsp->lref && lsp->lref < x25submax )
    {
	/*
	    Subnetwork ref is OK - is it configured in?
	*/

	if( xsndb[lsp->lref].regok )
	{
	    /*
		Resource available for the connect - MEDIUM PRIORITY?
	    */
	    if( (buf1=allocb(sizeof(struct ll_msgc),BPRI_MED)) != NULL )
	    {
		buf1->b_datap->db_type = M_PROTO;
		buf1->b_wptr += sizeof( struct ll_msgc );
		msg = (struct ll_msgc FAR *) buf1->b_rptr;
		msg->ll_type          = LL_CTL;
		msg->ll_command       = LC_CONNECT;
		msg->ll_connID        = lsp->lconnid;
		msg->ll_yourhandle    = 0;
		msg->ll_myhandle      = lsp->myref;
		msg->ll_service_class = (unsigned char) sclass;

		if( lsp->ldomain == LAN84 || lsp->ldomain == LAN88 )
		{ 
		    msg->ll_remsize = (unsigned char) rema->lsap_len;
		    msg->ll_locsize = (unsigned char) loca->lsap_len;
		    bcopy((BUFP_T)&rema->lsap_add[0],
		          (BUFP_T)&msg->ll_remaddr[0],LSAPMAXSIZE);
		    bcopy((BUFP_T)&loca->lsap_add[0],
		          (BUFP_T)&msg->ll_locaddr[0],LSAPMAXSIZE);
		}
		else
		{
#ifdef NO_WAN_CONTROL
		    msg->ll_remsize = msg->ll_locsize = 0;
#else
		    msg->ll_remsize = (unsigned char) rema->lsap_len;
		    bcopy((BUFP_T)&rema->lsap_add[0],
		          (BUFP_T)&msg->ll_remaddr[0],LSAPMAXSIZE);
#endif
		}
		x25lwput( xsndb[lsp->lref].wq,buf1);
		return(0);
	    }
	    else
		return(163);
	}                       /* Else not regok    */
    }                           /* Else out of range */

    return(130);                /* ERROR reject the connect request */
}


/************************************************************************/
int LL_prtymsg(lref,hdr)
/************************************************************************/

/*
    Send prty msg to the link level identified by the linkref lref
    (NB there may be no PLP data base so lref is the only hook).
*/

int lref;
mblk_t *hdr;

{
    if( 0<= lref && lref < x25submax )
    {
	/*
	    Subnetwork ref is OK - is it configured in?
	*/
	if( xsndb[lref].regok )
	{
	    hdr->b_datap->db_type = M_PCPROTO;
	    putnext( xsndb[lref].wq,hdr);
	    return(1);
	}
    }

    m_freem(hdr);   /* FREE the prty msg        */
    return(0);      /* ERROR reject the request */
}


/************************************************************************/
int LL_enable(lsp)
/************************************************************************/

/*
    Unblock any flow control on the lower stream.
*/

struct lsformat FAR *lsp;
{
register struct ll_msg FAR *msg;

if( 0<= lsp->lref && lsp->lref < x25submax )
    {

    /* Subnetwork ref is OK - is it configured in? */

    if( xsndb[lsp->lref].regok )
	{
	qenable( xsndb[lsp->lref].rq);
	return(1);
	}
    }

return(0);
}


/************************************************************************/
struct xsndbf *nxt_subnet()
/************************************************************************/

/*
    Returns pointer to the next free subnetwork record
    (as indicated by 'linked' field).
*/

{
    int i;

    for(i=0; i < x25submax; i++)
    {
	if( xsndb[i].linked == 0 )
	    return(&xsndb[i]);
    }

    return(NULL);
}


/************************************************************************/
void x25_trace(q,lsp,mp,received)
/************************************************************************/

/*
    Sends message up the trace queue.
*/

queue_t *q;
struct lsformat *lsp;
mblk_t *mp;
int received;

{
    register mblk_t *cmp;
    mblk_t *dmp;
  	char *cp ; 
	int   i ;
    
    trc_types FAR *trc_msg;

    static unsigned int trace_seq = 0;

    trace_seq++;

    if ( canput(q->q_next) )
    {
	if ((cmp = allocb(sizeof(trc_types), BPRI_LO)))
	{
	    if (dmp = copymsg(mp))
	    {
			pullupmsg(dmp,-1) ;

	    	cmp->b_datap->db_type = M_PROTO;
	        cmp->b_wptr += sizeof(trc_types);

		trc_msg = (trc_types FAR *)cmp->b_rptr;
		
		trc_msg->trc_prim = TR_X25_DAT;
		trc_msg->trc_hdr.trc_seq  = trace_seq;
		trc_msg->trc_hdr.trc_snid = lsp->lu_ident;
		trc_msg->trc_hdr.trc_time = curtime();
		trc_msg->trc_hdr.trc_rcv  = received;
		trc_msg->trc_hdr.trc_mid  = X25_STID;

#if ENDIAN_SWAP
		SWAP_THIS(trc_msg, sizeof(struct trc_ctl)) ;
#endif
#if 0
		
		if(mp->b_cont)
		{
			printf("x25trace = %x",received) ;
			cp = mp->b_cont->b_rptr ; 
			for(i = 0 ; i < 8 ; i++)
			{
				printf("[%x]=%2x",i,*cp) ;
				cp++ ;
			}
	
			cp = dmp->b_cont->b_rptr ;
			for(i = 0 ; i < 8 ; i++)
			{
				printf("[%x]=%2x",i,*cp) ;
				cp++ ;
			}
		}
		else
		{
			printf("x25trace no b_cont") ;

			printf("x25trace = %x ",received) ;
			cp = mp->b_rptr ; 
			for(i = 0 ; i < 8 ; i++)
			{
				printf("[%x]=%2x",i,*cp) ;
				cp++ ;
			}
	
			cp = dmp->b_rptr ;
			for(i = 0 ; i < 8 ; i++)
			{
				printf("[%x]=%2x",i,*cp) ;
				cp++ ;
			}
		}
#endif
		
		cmp->b_cont = dmp;
		
	        putnext(q,cmp);
	    }
	    else
	        freemsg(cmp);
	}
    }
}

