home *** CD-ROM | disk | FTP | other *** search
- /* net/rom level 4 (transport) protocol user level calls
- * Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
- * non-commercial distribution only.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include <stdarg.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "ax25.h"
- #include "lapb.h"
- #include "netrom.h"
- #include "nr4.h"
-
- #undef NR4DEBUG
-
- /* Open a NET/ROM transport connection */
- struct nr4cb *open_nr4(struct ax25_addr *node, struct ax25_addr *user,
- void (*r_upcall)(), void (*t_upcall)(),
- void (*s_upcall)(), char *puser)
- {
- struct nr4cb *cb ;
- struct nr4hdr hdr ;
-
- if ((cb = new_n4circ()) == NULLNR4CB)
- return NULLNR4CB ; /* No circuits available */
-
- /* Stuff what info we can into control block */
-
- cb->user = *node ; /* When we initiate, user is remote node */
- cb->node = *node ;
- cb->luser = *user ; /* Save local user for connect retries */
- cb->r_upcall = r_upcall ;
- cb->t_upcall = t_upcall ;
- cb->s_upcall = s_upcall ;
- cb->puser = puser ;
-
- /* Format connect request header */
-
- hdr.opcode = NR4OPCONRQ ;
- hdr.u.conreq.myindex = cb->mynum ;
- hdr.u.conreq.myid = cb->myid ;
- hdr.u.conreq.window = Nr4window ;
- hdr.u.conreq.user = *user ;
-
- /* The choice of mycall here is suspect. If I have a unique */
- /* callsign per interface, then a layer violation will be */
- /* required to determine the "real" callsign for my (virtual) */
- /* node. This suggests that callsign-per-interface is not */
- /* desirable, which answers *that* particular open question. */
-
- hdr.u.conreq.node = mycall ;
-
- /* Set and start connection retry timer */
-
- cb->cdtries = 1 ;
- cb->srtt = Nr4irtt ;
- cb->tcd.start = (2 * cb->srtt) / MSPTICK ;
- cb->tcd.func = nr4cdtimeout ;
- cb->tcd.arg = (char *)cb ;
- start_timer(&cb->tcd) ;
-
- /* Send connect request packet */
-
- nr4sframe(node, &hdr, NULLBUF) ;
-
- /* Set up initial state and signal state change */
-
- cb->state = NR4STDISC ;
- nr4state(cb, NR4STCPEND) ;
-
- /* Return control block address */
-
- return cb ;
- }
-
- /* Send a net/rom transport data packet */
- int send_nr4(struct nr4cb *cb, struct mbuf *bp)
- {
- if (cb == NULLNR4CB || bp == NULLBUF)
- return -1 ;
- enqueue(&cb->txq,bp) ;
- return nr4output(cb) ;
- }
-
- /* Do printf on a net/rom connection */
- int nr4_printf(struct nr4cb *cb, char *message, ...)
- {
- va_list argptr;
- struct mbuf *bp;
- int len;
- register char *cp;
-
- if(cb == NULLNR4CB)
- return 0;
-
- if((bp = alloc_mbuf(512)) != NULLBUF)
- {
- cp = bp->data;
- va_start(argptr,message);
- len = vsprintf(cp,message,argptr);
- va_end(argptr);
- cp = bp->data;
- bp->cnt = (strlen(cp));
- send_nr4(cb,bp);
- return len;
- }
- else
- {
- return 0;
- }
- }
-
- /* Receive incoming net/rom transport data */
- struct mbuf *recv_nr4(struct nr4cb *cb, int16 cnt)
- {
- struct mbuf *bp ;
-
- cnt = cnt;
-
- if (cb->rxq == NULLBUF)
- return NULLBUF ;
-
- bp = cb->rxq ; /* Just give `em everything */
- cb->rxq = NULLBUF ;
-
- /* Since we took everything, we always go unchoked. If we */
- /* ever change this code to use cnt, or make it a real packet */
- /* delivery, there will have to be a check to see if the queue */
- /* has gotten short enough yet. */
-
- if (cb->qfull) {
- cb->qfull = 0 ; /* Choke flag off */
- nr4ackit((char *)cb) ; /* Get things rolling again */
- }
-
- return bp ;
- }
-
- /* Close a NET/ROM connection */
- void disc_nr4(struct nr4cb *cb)
- {
- struct nr4hdr hdr ;
-
- if (cb->state != NR4STCON)
- return ;
-
- /* Format disconnect request packet */
-
- hdr.opcode = NR4OPDISRQ ;
- hdr.yourindex = cb->yournum ;
- hdr.yourid = cb->yourid ;
-
- /* Set and start timer */
-
- cb->cdtries = 1 ;
- cb->tcd.start = (2 * cb->srtt) / MSPTICK ;
- cb->tcd.func = nr4cdtimeout ;
- cb->tcd.arg = (char *)cb ;
- start_timer(&cb->tcd) ;
-
- /* Send packet */
-
- nr4sframe(&cb->node, &hdr, NULLBUF) ;
-
- /* Signal state change. nr4state will take care of */
- /* stopping the appropriate timers and resetting */
- /* window pointers. */
-
- nr4state(cb, NR4STDPEND) ;
-
- }
-
- /* Abruptly terminate a NET/ROM transport connection */
- void reset_nr4(struct nr4cb *cb)
- {
- cb->dreason = NR4RRESET ;
- nr4state(cb,NR4STDISC) ;
- }
-
-
- /* Force retransmission on a NET/ROM transport connection */
- int kick_nr4(struct nr4cb *cb)
- {
- unsigned seq ;
- struct timer *t ;
-
- if(!nr4valcb(cb))
- return -1 ;
-
- switch (cb->state) {
- case NR4STCPEND:
- case NR4STDPEND:
- stop_timer(&cb->tcd) ;
- nr4cdtimeout((char *)cb) ;
- break ;
-
- case NR4STCON:
- if (cb->nextosend != cb->ackxpected) { /* if send window is open: */
- for (seq = cb->ackxpected ;
- nr4between(cb->ackxpected, seq, cb->nextosend) ;
- seq = (seq + 1) & NR4SEQMASK) {
- t = &cb->txbufs[seq % cb->window].tretry ;
- stop_timer(t) ;
- t->state = TIMER_EXPIRE ; /* fool retry routine */
- }
- nr4txtimeout((char *)cb) ;
- }
- break ;
- }
-
- return 0 ;
- }
-
-