Category : Network Files
Archive   : KA9Q.ZIP
Filename : SLFP.C

 
Output of file : SLFP.C contained in archive : KA9Q.ZIP
/* Send and receive IP datagrams on serial lines. Compatible with SL/FP
* as used with the Merit Network and MIT.
*/
#include "config.h"
#ifdef SLFP

#include
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "ip.h"
#include "slfp.h"

#ifdef UNIX /* BSD or SYS5 */
#include "unix.h"
#endif

#include "asy.h"
#ifdef MSDOS
#include "8250.h"
#endif
#include "trace.h"

int asy_ioctl();
int slfp_send();
int doslfp();
int asy_output();

/* SL/FP level control structure */
struct slfp slfp[ASY_MAX];
char slfp_ack[ACK_LEN] = { SLFP_ACK } ;
char slfp_req[REQ_LEN] = { SLFP_REQ } ;
char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ; /* IP Packet Header */
char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ; /* "Addr Req" Packet Header */
struct interface asy_interface = /* Fake interface for "dump" proc */
{ NULLIF, "asy" } ; /* Name of "asy" interface */

/* Routine to Initialize the Async line for SL/FP processing.
* Mostly involves requesting the IP Address for this host.
*/
int
slfp_init(interface,modem_cmd)
struct interface *interface ;
char *modem_cmd ; /* optional command to Modem */
{
register struct slfp *sp;
register struct timer *ar ;
char *modem_line ;
int i ;

sp = &slfp[interface->dev];
ar = &sp->ar_timer ;

slfp[interface->dev].req_pending = 0 ;

/* If a Modem Command is present, send it and wait for Connection */
if (modem_cmd != NULLCHAR) {
char c; c='\r';
modem_line = (char *)malloc(strlen(modem_cmd)+2) ;
if (modem_line == NULLCHAR)
return -1 ;
strcpy(modem_line, modem_cmd);
strcat(modem_line, "\r") ;
asy_output(interface->dev,&c,1); /* Wake up modem */
set_timer(ar,500);
start_timer(ar);
while(ar->state == TIMER_RUN)
keep_things_going();
asy_output(interface->dev,modem_line,strlen(modem_line));
free(modem_line);
set_timer(ar, 30000) ; /* Wait up to 30 seconds for Connection */
start_timer(ar);
} else
set_timer(ar, 500) ; /* Wait half a second before sending REQs */

if (ip_addr == 0) { /* Ask network for my IP address... */
sp->ar_pending = 1 ;

/* Request an Address up to 4 times (every 10 seconds) before giving up */
for (i=0; i<4; i++) {
start_timer(ar) ;
while (sp->ar_pending && (ar->state == TIMER_RUN)) {
keep_things_going() ; /* Can't return until timeout or addr */
if(kbread()==(-2)) /* Hit the Escape key */
return(-1);
}
if (!sp->ar_pending) {
return 0 ;
}
slfp_send(NULLBUF, interface, 0L, 0, 0, 0, 0) ;
set_timer(ar, 10000) ; /* Wait up to 10 seconds for IP Addr */
}

sp->ar_pending = 0 ;
return -1 ;
} else
return 0;
}

/* Send routine for point-to-point slfp
* This is a trivial function since slfp_encode adds the link-level header
*/
int
slfp_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp; /* Buffer to send */
struct interface *interface; /* Pointer to interface control block */
int32 gateway;
char precedence;
char delay;
char throughput;
char reliability;
{
if(interface == NULLIF){
free_p(bp);
return;
}
dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
(*interface->raw)(interface,bp);
}
/* Send a raw slfp frame -- also trivial */
slfp_raw(interface,bp)
struct interface *interface;
struct mbuf *bp;
{
/* Make "asy" interface a shadow of the SLFP interface */
asy_interface.trace = interface->trace ;

/* Queue a frame on the slfp output queue and start transmitter */
slfpq(interface->dev,bp);
}
/* Encode a raw packet in slfp framing, put on link output queue, and kick
* transmitter
*/
static
slfpq(dev,bp)
int16 dev; /* Serial line number */
struct mbuf *bp; /* Buffer to be sent */
{
register struct slfp *sp;
struct mbuf *slfp_encode();

if((bp = slfp_encode(dev,bp)) == NULLBUF)
return;

sp = &slfp[dev];
enqueue(&sp->sndq,bp);
dump(&asy_interface,IF_TRACE_OUT,TRACE_SLFP,bp);
sp->sndcnt++;
if(sp->tbp == NULLBUF)
slfp_asy_start(dev);
}

/* Handle REQ-ACK Timer expiration
*/
void
slfp_req_notify(dev)
int16 dev;
{
register struct slfp *sp;
register struct timer *rt ; /* Timer for REQ-ACK negotiation */
struct mbuf *bp ;

sp = &slfp[dev];
rt = &(sp->req_timer) ;
if (sp->reqcnt++ >= 10) {
sp->tbp = NULLBUF ;
sp->req_pending = 0 ;
bp = dequeue(&sp->sndq);
sp->sndcnt--;
free_p(bp) ;
}
else {
set_timer(rt,2000) ; /* 2-Second Timeout for ACK */
start_timer(rt) ;
asy_output(dev, slfp_req, REQ_LEN) ;
}
}

/* Start output, if possible, on asynch device dev */
static
slfp_asy_start(dev)
int16 dev;
{
register struct slfp *sp;
register struct timer *rt ; /* Timer for REQ-ACK negotiation */
struct mbuf *bp ;

if(!stxrdy(dev))
return; /* Transmitter not ready */

sp = &slfp[dev];
bp = sp->tbp ;
if(bp != NULLBUF){
/* transmission just completed */
free_p(bp) ;
sp->tbp = NULLBUF;
}
if(sp->sndq == NULLBUF)
return; /* No work */

rt = &(sp->req_timer) ;
if (sp->req_pending)
return ;
sp->reqcnt = 0 ;
sp->req_pending = 1 ;
rt->func = slfp_req_notify ;
rt->arg = (char *)dev ;
set_timer(rt,2000) ; /* 2-Second Timeout for ACK */
start_timer(rt) ;
asy_output(dev, slfp_req, REQ_LEN) ;
}
/* Encode a packet in SL/FP format */
static
struct mbuf *
slfp_encode(dev,bp)
int16 dev; /* Serial line number */
struct mbuf *bp;
{
struct mbuf *lbp; /* Mbuf containing line-ready packet */
register char *cp;
char c;

/* Allocate output mbuf that's twice as long as the packet.
* This is a worst-case guess (consider a packet full of SLFP_ENDs!)
*/
lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2);
if(lbp == NULLBUF){
/* No space; drop */
free_p(bp);
return NULLBUF;
}
cp = lbp->data;

/* Prefix packet with the Correct Link-Level Header */
if (slfp[dev].ar_pending)
memcpy(cp, ar_hdr, HDR_LEN) ;
else
memcpy(cp, ip_hdr, HDR_LEN) ;
cp += HDR_LEN ;

/* Copy input to output, escaping special characters */
while(pullup(&bp,&c,1) == 1){
switch(c & 0xff){
case SLFP_ESC:
*cp++ = SLFP_ESC;
*cp++ = SLFP_ESC - SLFP_ESC;
break;
case SLFP_END:
*cp++ = SLFP_ESC;
*cp++ = SLFP_END - SLFP_ESC;
break;
case SLFP_ACK:
*cp++ = SLFP_ESC;
*cp++ = SLFP_ACK - SLFP_ESC;
break;
case SLFP_REQ:
*cp++ = SLFP_ESC;
*cp++ = SLFP_REQ - SLFP_ESC;
break;
default:
*cp++ = c;
}
}
*cp++ = SLFP_END;
lbp->cnt = cp - lbp->data;
return lbp;
}

#ifdef MSDOS
/* Invoked when SLFP_REQ is received during xmit of outgoing packet.
* This allows immediate reception of packet from SCP, rather than
* forcing it to buffer it until we finish sending the outgoing packet
*/
static
unsigned
slfp_urgent(dev)
int16 dev; /* SL/FP unit number */
{
register struct dma *dp ;

dp = &asy[dev].dma ;
if (dp->last_octet == SLFP_ESC)
return 256 ;
else {
asy[dev].urgent = NULLCHAR ;
return SLFP_ACK ;
}
}
#endif

void
hndl_rcvd_req(dev, sp)
int16 dev; /* SL/FP unit number */
register struct slfp *sp;
{
char i_state ;

if (sp->reqd) { /* REQ before rcv'g END of last Packet! */
sp->missed_ends++ ;
free_p(sp->rbp); /* throw away current packet */
sp->rbp = NULLBUF;
sp->rcnt = 0;
}

sp->reqd = 1 ;
i_state = disable() ;
#ifdef MSDOS
if (asy[dev].dma.flags)
asy[dev].urgent = slfp_urgent ;
else
#endif
asy_output(dev, slfp_ack, ACK_LEN) ;
restore(i_state) ;
}

void
hndl_rcvd_ack(dev, sp)
int16 dev; /* SL/FP unit number */
register struct slfp *sp;
{
char i_state ;

i_state = disable() ;
if (sp->req_pending == 0) {
sp->false_acks++ ;
restore(i_state) ;
return ;
}
sp->req_pending = 0 ;
stop_timer(&(sp->req_timer)) ;
restore(i_state) ;
sp->tbp = dequeue(&sp->sndq);
sp->sndcnt--;
asy_output(dev,sp->tbp->data,sp->tbp->cnt);
}

/* Process incoming bytes in SL/FP format
* When a buffer is complete, return it; otherwise NULLBUF
*/
static
struct mbuf *
slfp_decode(dev,c)
int16 dev; /* SL/FP unit number */
char c; /* Incoming character */
{
struct mbuf *bp;
register struct slfp *sp;
unsigned char uc ;

sp = &slfp[dev];

uc = c & 0xff;
if (uc == SLFP_REQ) {
hndl_rcvd_req(dev, sp) ;
return NULLBUF ;
}
if (uc == SLFP_ACK) {
hndl_rcvd_ack(dev, sp) ;
return NULLBUF ;
}
if (sp->reqd == 0) {
return NULLBUF ;
}

switch(uc){
case SLFP_END:
sp->reqd = 0 ;
/* Kick upstairs */
bp = sp->rbp;
sp->rbp = NULLBUF;
sp->rcnt = 0;
return bp;
break ;

case SLFP_ESC:
sp->escaped = 1;
return NULLBUF;
}
if(sp->escaped){
sp->escaped = 0;
uc += SLFP_ESC;
switch(uc){
case SLFP_ESC:
case SLFP_REQ:
case SLFP_ACK:
case SLFP_END:
break;
default:
uc -= SLFP_ESC;
sp->bad_esc++;
sp->errors++;
}
}
/* We reach here with a character for the buffer;
* make sure there's space for it
*/
if(sp->rbp == NULLBUF){
/* Allocate first mbuf for new packet */
if((sp->rbp1 = sp->rbp = alloc_mbuf(SLFP_ALLOC)) == NULLBUF)
return NULLBUF; /* No memory, drop */
sp->rcp = sp->rbp->data;
} else if(sp->rbp1->cnt == SLFP_ALLOC){
/* Current mbuf is full; link in another */
if((sp->rbp1->next = alloc_mbuf(SLFP_ALLOC)) == NULLBUF){
/* No memory, drop whole thing */
free_p(sp->rbp);
sp->rbp = NULLBUF;
sp->rcnt = 0;
return NULLBUF;
}
sp->rbp1 = sp->rbp1->next;
sp->rcp = sp->rbp1->data;
}
/* Store the character, increment fragment and total
* byte counts
*/
*sp->rcp++ = uc;
sp->rbp1->cnt++;
sp->rcnt++;
return NULLBUF;
}
/* Process SL/FP line I/O */
int
doslfp(interface)
struct interface *interface;
{
char c;
struct mbuf *bp, *cp=NULLBUF;
int16 dev;
int16 asy_recv();

dev = interface->dev;
/* Process any pending input */
while(asy_recv(dev,&c,1) != 0) {
if((bp = slfp_decode(dev,c)) != NULLBUF) {
(*slfp[dev].recv)(interface,bp);
}
}
if (cp != NULLBUF)
(*slfp[dev].recv)(interface,cp);

/* Kick the transmitter if it's idle */
if(stxrdy(dev))
slfp_asy_start(dev);
}

/* Handle Address Reply packets
*/
void
addr_reply(dev,bp)
int16 dev;
struct mbuf *bp;
{
if (len_mbuf(bp) != 4) { /* Invalid Address Response */
free_p(bp) ;
return ;
}
if (!slfp[dev].ar_pending) {
free_p(bp) ;
return ;
}
stop_timer(&slfp[dev].ar_timer) ;
slfp[dev].ar_pending = 0 ;
ip_addr = (unsigned char)(*bp->data++) ;
ip_addr <<= 8 ;
ip_addr |= (unsigned char)(*bp->data++) ;
ip_addr <<= 8 ;
ip_addr |= (unsigned char)(*bp->data++) ;
ip_addr <<= 8 ;
ip_addr |= (unsigned char)(*bp->data++) ;
free_p(bp) ;
}

/* Unwrap incoming SL/FP packets -- use link level header to determine
* how to handle packet
*/
slfp_recv(interface,bp)
struct interface *interface;
struct mbuf *bp;
{
void ip_route();

dump(interface,IF_TRACE_IN,TRACE_SLFP,bp);
if (len_mbuf(bp) < HDR_LEN) {
free_p(bp) ;
return ;
}
if (memcmp(ip_hdr, bp->data, HDR_LEN) == 0) {
bp->data += HDR_LEN ;
bp->cnt -= HDR_LEN ;
dump(interface,IF_TRACE_IN,TRACE_IP,bp);
ip_route(bp,0); /* By def'n, all inbound packets are addr'd to us */
}
else if (memcmp(ar_hdr, bp->data, HDR_LEN) == 0) {
bp->data += HDR_LEN ;
bp->cnt -= HDR_LEN ;
dump(interface,IF_TRACE_IN,TRACE_IP,bp);
addr_reply(interface->dev,bp);
} else {
dump(interface,IF_TRACE_IN,TRACE_IP,bp);
free_p(bp) ;
}
}

int
slfp_dump(bpp, check)
struct mbuf **bpp;
int check ;
{
if(bpp == NULLBUFP || *bpp == NULLBUF)
return 0;

printf("SLFP: ");
/* Sneak peek at IP header and find length */
if (len_mbuf(*bpp) < HDR_LEN) {
printf("packet too short!\n");
return 0;
}

if (memcmp(ip_hdr, (*bpp)->data, HDR_LEN) == 0)
printf("IP Packet\n") ;
else if (memcmp(ar_hdr, (*bpp)->data, HDR_LEN) == 0)
printf("Addr Req Packet\n") ;
else
printf("bad header\n") ;


return 0 ;
}

#endif /* SLFP */


  3 Responses to “Category : Network Files
Archive   : KA9Q.ZIP
Filename : SLFP.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/