home *** CD-ROM | disk | FTP | other *** search
- /* 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;
- /*
- printf("Tx: len %d/%d -> ", len, lenq);
- */
- *q |= sl_compress_tcp(&q, &len, slip[dev].slcomp, 1);
-
- if (*q & 0x80)
- slip[dev].stat_tcp_compressed_sent += 1;
- else if (*q >= 0x70)
- slip[dev].stat_tcp_uncompressed_sent += 1;
- else
- slip[dev].stat_ip_sent += 1;
- /*
- printf("%d \n", len);
- line = (line+1)%16;
- */
- m = qdata(q, len);
- if (!ms)
- ms = m;
- if (!mp)
- mp = m;
- else
- {
- mp->anext = m;
- mp = m;
- }
- free(p);
- }
-
- return ms;
- }
-
- static struct mbuf *slip_uncompress(int dev, struct mbuf *bp)
- {
- int len = len_mbuf(bp);
- int type;
- char *p, *q;
-
- if (slip[dev].slcomp==NULL)
- {
- slip[dev].stat_ip_recvd += 1;
- return bp;
- }
-
- if (p = (char *)malloc(len+128), p==NULL)
- return bp;
-
- pullup(&bp, p+128, len);
-
- if (p[128] & 0x80)
- type = TYPE_COMPRESSED_TCP;
- else if (p[128] >= 0x70)
- {
- type = TYPE_UNCOMPRESSED_TCP;
- p[128] &=~ 0x30;
- } else
- type = TYPE_IP;
-
- /*
- bbc_vdu(4);
- bbc_vdu(26);
- bbc_vdu(30);
-
- printf("Rx: type %.2x len %d -> ", type, len);
- */
- q = sl_uncompress_tcp(p+128, &len, type, slip[dev].slcomp);
- /*
- printf("%d \n", (q)?len:0);
- */
- if (q)
- {
- bp = qdata(q, len);
- if (type==TYPE_IP)
- slip[dev].stat_ip_recvd += 1;
- else if (type==TYPE_COMPRESSED_TCP)
- slip[dev].stat_tcp_compressed_recvd += 1;
- else if (type==TYPE_UNCOMPRESSED_TCP)
- slip[dev].stat_tcp_uncompressed_recvd += 1;
- }
- else
- {
- bp = qdata(p+128, len);
- slip[dev].stat_bad_recvd += 1;
- }
- free(p);
- return bp;
- }
-