/*     
 *     x-kernel v3.3
 *
 *     Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 */

#include "xkernel.h"
#include "ip.h"
#include "prot/swp.h"

#define SWP_MAX_WINDOW  127
#define SWP_MAX_SEQ	(SWP_MAX_WINDOW * 2 + 1)
#define SWP_DEF_WINDOW  10
#define SWP_TIMEOUT	(200 * 1000)		/* 200 msec */
#define SWP_TICK	(SWP_TIMEOUT / 2)

/* SWP message header definition */
typedef struct header {
    SWPport sport;		/* source */
    SWPport dport;		/* dest */
    u_short ulen;		/* length */
    SWPsws seq;		        /* sequence */
    SWPsws windowsize;	        /* window size */
    u_short flags;		/* flag bits */
} SWPhdr;

#define HLEN (sizeof(SWPhdr))

/* protocol state */
typedef struct pstate {
    Map activemap;
    Map passivemap;
    Event timer;		/* periodic retransmission timer */
} ProtlState;

typedef struct {
    int valid;
    XTime last_sent;		/* time of last retransmission */
    Sessn lls;			/* session packet belongs to */
    Msg   packet;
} sendqelem;

typedef struct {
    int valid;
    Msg packet;
} recvqelem;

/* session state */
typedef struct sstate {
    SWPhdr hdr;			/* partially filled in template */
    Event event;		/* timeout event */
    int inuse;			/* true if data is flowing */
    int seqsize;		/* max sequence + 1 */
    SWPsws windowsize;	        /* window size */

    /* sender */
    SWPsws lowest_unack;	/* lowest unacknowledged seq */
    SWPsws next_seq;		/* next seq to send */
    Semaphore canSend;		/* block when window is full */
    sendqelem *sendq;		/* var sized array, retransmission queue */

    /* receiver */
    SWPsws next_ack;		/* next ack to send */
    recvqelem *recvq;		/* var sized array, out-of-order packet */
} SessnState;

/* active and passive maps */
typedef struct {
    Sessn   lls;
    SWPport localport;
    SWPport remoteport;
} ActiveId;

typedef SWPport PassiveId;

#define ACTIVE_MAP_SIZE  101
#define PASSIVE_MAP_SIZE 23

/* header flag bits */
#define SWP_FLAG_ACK	0x0001		/* ack if set, data if cleared */

/* UPI function declarations */
void            swp_init(Protl);
static Sessn    swpOpen(Protl, Protl, Protl, Part *);
static XkReturn swpOpenEnable(Protl, Protl, Protl, Part *);
static XkReturn swpDemux(Protl, Sessn, Msg *);
static XkHandle swpPush(Sessn, Msg *);
static XkReturn swpPop(Sessn, Sessn, Msg *, void *);
static Sessn    swpCreateSessn(Protl, Protl, Protl, ActiveId *);
static XkReturn swpClose(Sessn);
static int      swpControlProtl(Protl, int, char *, int) ;
static int      swpControlSessn(Sessn, int, char *, int) ;
static Part    *swpGetParticipants(Sessn);

/* internal function declarations */

static void     getproc_protl(Protl);
static void	setWindowSize(SessnState *, int);
static void     getproc_sessn(Sessn);
static long     swpHdrLoad(SWPhdr *, char *, long);
static void     swpHdrStore(SWPhdr *, char *, long);
static void	sendqEnqueue(sendqelem *, Sessn, Msg *, SWPsws);
static void	sendqDequeue(sendqelem *, SWPsws);
static void	recvqEnqueue(recvqelem *, Msg *, SWPsws);
static void	recvqDequeue(recvqelem *, SWPsws);
static void	swpTimeout(Event, void *);

/* trace variable used in conjunction with xTrace stmts */
int traceswpp;
