home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 3
/
PDCD_3.iso
/
internet
/
tcpipsrc
/
Drivers
/
c
/
SLIP
< prev
Wrap
Text File
|
1995-02-20
|
10KB
|
427 lines
/* Send and receive IP datagrams on serial lines. Compatible with SLIP
* under Berkeley Unix.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "ax25.h"
#include "slip.h"
#include "asy.h"
#include "trace.h"
#include "timer.h"
#include "ip.h"
#include "arc.h"
#include "bbc.h"
static int slipq(int, struct mbuf *);
static void asy_start(int);
static struct mbuf *slip_encode(struct mbuf *);
static struct mbuf *slip_decode(int, char);
static struct mbuf *slip_uncompress(int dev, struct mbuf *bp);
static struct mbuf *slip_compress(int dev, struct mbuf *bp);
/* Slip level control structure */
struct slip slip[ASY_MAX];
int doslipstat(int argc, char**argv)
{
struct interface *iface;
if (iface = if_lookup(argv[1]), iface!=NULL)
{
cwprintf(NULL, "Statistics for %s interface %s:\r\n", (slip[iface->dev].slcomp)?"CSLIP":"SLIP", iface->name);
cwprintf(NULL, " IP frames sent : %d\r\n", slip[iface->dev].stat_ip_sent);
if (slip[iface->dev].slcomp)
{
cwprintf(NULL, " TCP Compressed frames sent : %d\r\n", slip[iface->dev].stat_tcp_compressed_sent);
cwprintf(NULL, " TCP Uncompressed frames sent : %d\r\n", slip[iface->dev].stat_tcp_uncompressed_sent);
}
cwprintf(NULL, " IP frames recvd : %d\r\n", slip[iface->dev].stat_ip_recvd);
if (slip[iface->dev].slcomp)
{
cwprintf(NULL, " TCP Compressed frames recvd : %d\r\n", slip[iface->dev].stat_tcp_compressed_recvd);
cwprintf(NULL, " TCP Uncompressed frames recvd: %d\r\n", slip[iface->dev].stat_tcp_uncompressed_recvd);
}
cwprintf(NULL, " Bad frames recvd : %d\r\n", slip[iface->dev].stat_bad_recvd);
}
else
{
cwprintf(NULL, "Interface %s unknown\r\n", argv[1]);
return 1;
}
return 0;
}
/* Send routine for point-to-point slip
* This is a trivial function since there is no slip link-level header
*/
int slip_send(struct mbuf *data, struct interface *interface,
int32 gateway, char precedence, char delay,
char throughput, char reliability)
{
gateway = gateway;
precedence = precedence;
delay = delay;
throughput = throughput;
reliability = reliability;
if (interface == NULLIF)
{
free_p(data);
return -1;
}
dump(interface, IF_TRACE_OUT, TRACE_IP, data);
return (*interface->raw)(interface, data);
}
/* Send a raw slip frame -- also trivial */
int slip_raw(struct interface *interface, struct mbuf *data)
{
/* Queue a frame on the slip output queue and start transmitter */
return slipq(interface->dev,data);
}
/* Encode a raw packet in slip framing, put on link output queue, and kick
* transmitter */
static int slipq(int dev, struct mbuf *data)
{
register struct slip *sp;
struct mbuf *bp;
bp = slip_compress(dev, data);
if((bp = slip_encode(bp)) == NULLBUF)
return -1;
sp = &slip[dev];
enqueue(&sp->sndq,bp);
sp->sndcnt++;
if(sp->tbp == NULLBUF)
asy_start(dev);
return 0;
}
/* Start output, if possible, on asynch device dev
Due to the way that the serial port works on the Arc it is not
possible to get a serial transmit status. Therefore if asy_output
fails to complete the job of writing cnt characters, store the
remainder of the frame temporarily until the next call to asy_start,
then transmit the rest of the frame. Otherwise take the next packet
from the queue.
*/
static void asy_start(int dev)
{
register struct slip *sp;
static int asy_failed = 0;
static char *asy_buffer;
static int asy_length;
char *temp_buffer;
int temp_length;
int n;
if (asy_failed)
{
if ((n = asy_output(dev, asy_buffer, asy_length)) < asy_length)
{
temp_length = asy_length - n;
temp_buffer = malloc(temp_length);
memcpy(temp_buffer, asy_buffer + n, temp_length);
free(asy_buffer);
asy_length = temp_length;
asy_buffer = temp_buffer;
}
else
{
asy_failed = 0;
free(asy_buffer);
}
}
if (!asy_failed)
{
sp = &slip[dev];
if (sp->tbp != NULLBUF)
{
/* transmission just completed */
free_p(sp->tbp);
sp->tbp = NULLBUF;
}
if (sp->sndq == NULLBUF)
return; /* No work */
sp->tbp = dequeue(&sp->sndq);
sp->sndcnt--;
if ((n = asy_output(dev, sp->tbp->data, sp->tbp->cnt)) < sp->tbp->cnt)
{
asy_failed = 1;
asy_length = sp->tbp->cnt - n;
asy_buffer = malloc(asy_length);
memcpy(asy_buffer, sp->tbp->data + n, asy_length);
}
}
}
/* Encode a packet in SLIP format */
static struct mbuf *slip_encode(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 FR_ENDs!) */
lbp = alloc_mbuf(2 * len_mbuf(bp) + 2);
if(lbp == NULLBUF)
{
/* No space; drop */
free_p(bp);
return NULLBUF;
}
cp = lbp->data;
/* Flush out any line garbage */
*cp++ = FR_END;
/* Copy input to output, escaping special characters */
while (pullone(&bp, &c) == 1)
{
switch(uchar(c))
{
case FR_ESC:
*cp++ = FR_ESC;
*cp++ = T_FR_ESC;
break;
case FR_END:
*cp++ = FR_ESC;
*cp++ = T_FR_END;
break;
default:
*cp++ = c;
}
}
*cp++ = FR_END;
lbp->cnt = cp - lbp->data;
return lbp;
}
/* Process incoming bytes in SLIP format
* When a buffer is complete, return it; otherwise NULLBUF
*/
static struct mbuf *slip_decode(int dev, char c)
{
struct mbuf *bp;
register struct slip *sp;
sp = &slip[dev];
switch(c)
{
case FR_END:
bp = sp->rbp;
sp->rbp = NULL;
sp->rcnt = 0;
return bp; /* Will be NULLBUF if empty frame */
case FR_ESC:
sp->escaped = 1;
return NULL;
}
if(sp->escaped)
{
/* Translate 2-char escape sequence back to original char */
sp->escaped = 0;
switch(c)
{
case T_FR_ESC:
c = FR_ESC;
break;
case T_FR_END:
c = FR_END;
break;
default:
sp->errors++;
break;
}
}
/* We reach here with a character for the buffer;
make sure there's space for it */
if (sp->rbp == NULL)
{
/* Allocate first mbuf for new packet */
if ((sp->rbp1 = sp->rbp = alloc_mbuf(SLIP_ALLOC)) == NULL)
return NULL; /* No memory, drop */
sp->rcp = sp->rbp->data;
}
else if(sp->rbp1->cnt == SLIP_ALLOC)
{
/* Current mbuf is full; link in another */
if((sp->rbp1->next = alloc_mbuf(SLIP_ALLOC)) == NULL)
{
/* No memory, drop whole thing */
free_p(sp->rbp);
sp->rbp = NULL;
sp->rcnt = 0;
return NULL;
}
sp->rbp1 = sp->rbp1->next;
sp->rcp = sp->rbp1->data;
}
/* Store the character, increment fragment and total
byte counts */
*sp->rcp++ = c;
sp->rbp1->cnt++;
sp->rcnt++;
return NULL;
}
/* Process SLIP line I/O */
void doslip(struct interface *interface)
{
char c;
struct mbuf *bp;
int dev;
dev = interface->dev;
/* Process any pending input */
while(asy_recv(dev, &c) != 0)
{
if ((bp = slip_decode(dev, c)) != NULLBUF)
{
bp = slip_uncompress(dev, bp);
(*slip[dev].recv)(interface, bp);
}
}
/* Kick the transmitter if it's idle */
asy_start(dev);
}
/* Unwrap incoming SLIP packets -- trivial operation since there's no
* link level header
*/
void slip_recv(struct interface *interface, struct mbuf *bp)
{
/* By definition, all incoming packets are "addressed" to us */
dump(interface, IF_TRACE_IN, TRACE_IP, bp);
ip_route(bp, 0);
}
static struct mbuf *slip_compress(int dev, struct mbuf *bp)
{
/*
static int line = 0;
*/
int len, lenq;
char *p, *q;
struct mbuf *ms = NULL, *mp = NULL, *m = NULL;
if (slip[dev].slcomp==NULL)
{
slip[dev].stat_ip_sent += 1;
return bp;
}
/*
bbc_vdu(4);
bbc_vdu(26);
bbc_vduq(31, dev*40, line+1);
*/
while (bp)
{
len = len_mbuf(bp);
lenq = len_q(bp);
if (p = (char *)malloc(len), p==NULL)
return bp;
pullup(&bp, p, len);
q = p;
/