/* Send and receive IP datagrams on serial lines. Compatible with SLIP * under Berkeley Unix. */ #ifdef TRACE #include #endif #include "machdep.h" #ifdef TRACE #include "trace.h" #endif #include "mbuf.h" #include "iface.h" #include "ax25.h" #include "slip.h" #ifdef AMIGA #include "amiga.h" #else #include "pc.h" #endif int slip_send(); int doslip(); int asy_output(); /* Slip level control structure */ struct slip slip[ASY_MAX]; unsigned nasy; /* Send routine for point-to-point slip * This is a trivial function since there is no slip link-level header */ int slip_send(bp,interface,gateway,precedence,delay,throughput,reliability) struct mbuf *bp; /* Buffer to send */ struct interface *interface; /* Pointer to interface control block */ int32 gateway; /* Ignored (SLIP is point-to-point) */ char precedence; char delay; char throughput; char reliability; { /* Queue a frame on the slip output queue and start transmitter */ if(interface == NULLIF){ free_p(bp); return; } #ifdef TRACE if(trace & TRACE_SLIP){ printf("%s sent:\r\n",interface->name); if((trace & TRACE_HDR) > 2) ip_dump(bp); if(trace & TRACE_DUMP) hexdump(bp); if(trace & TRACE_ASCII) asciidump(bp); fflush(stdout); } #endif slipq(interface->dev,bp); } /* Encode a packet in slip framing, put on link output queue, and kick * transmitter */ slipq(dev,bp) int16 dev; /* Serial line number */ struct mbuf *bp; /* Buffer to be sent */ { register struct slip *sp; struct mbuf *slip_encode(); if((bp = slip_encode(bp)) == NULLBUF) return; sp = &slip[dev]; enqueue(&sp->sndq,bp); sp->sndcnt++; if(sp->tbp == NULLBUF) asy_start(dev); } /* Start output, if possible, on asynch device dev */ static asy_start(dev) int16 dev; { register struct slip *sp; if(!stxrdy(dev)) return; /* Transmitter not ready */ 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--; asy_output(dev,sp->tbp->data,sp->tbp->cnt); } /* Encode a packet in SLIP format */ static struct mbuf * slip_encode(bp) struct mbuf *bp; { struct mbuf *lbp; /* Mbuf containing line-ready packet */ register char *cp; register int cnt; 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; cnt = 0; /* Flush out any line garbage */ *cp++ = FR_END; cnt++; /* Copy input to output, escaping special characters */ while(pullup(&bp,&c,1) == 1){ switch(c & 0xff){ case FR_ESC: *cp++ = FR_ESC; *cp++ = T_FR_ESC; cnt += 2; break; case FR_END: *cp++ = FR_ESC; *cp++ = T_FR_END; cnt += 2; break; default: *cp++ = c; cnt++; } } *cp++ = FR_END; cnt++; lbp->cnt = cnt; return lbp; } /* Process incoming bytes in SLIP format * When a buffer is complete, return it; otherwise NULLBUF */ static struct mbuf * slip_decode(dev,c) int dev; /* Slip unit number */ char c; /* Incoming character */ { struct mbuf *bp,*nbp; register struct slip *sp; sp = &slip[dev]; switch(c & 0xff){ case FR_END: if(sp->rbp != NULLBUF){ /* Kick upstairs */ bp = sp->rbp; sp->rbp = NULLBUF; sp->rcnt = 0; /* Copy into contiguous buffer, if necessary */ if(bp->next != NULLBUF){ nbp = copy_p(bp,len_mbuf(bp)); free_p(bp); bp = nbp; } return bp; } return NULLBUF; case FR_ESC: sp->escaped = 1; return NULLBUF; } if(sp->escaped){ sp->escaped = 0; switch(c & 0xff){ case T_FR_ESC: c = FR_ESC; break; case T_FR_END: c = FR_END; break; default: sp->errors++; } } if(sp->rcnt == SLIP_MTU){ /* Packet is too large, drop it and start over */ free_p(sp->rbp); sp->rbp = NULLBUF; sp->rcnt = 0; return NULLBUF; } /* 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(SLIP_ALLOC)) == NULLBUF) return NULLBUF; /* 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)) == 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++ = c; sp->rbp1->cnt++; sp->rcnt++; return NULLBUF; } /* Process SLIP line I/O */ int doslip(interface) struct interface *interface; { char c; struct mbuf *bp; int16 dev; dev = interface->dev; /* Process any pending input */ while(asy_recv(dev,&c,1) != 0) if((bp = slip_decode(dev,c)) != NULLBUF) (*slip[dev].recv)(interface,bp); /* Kick the transmitter if it's idle */ if(stxrdy(dev)) asy_start(dev); } /* Unwrap incoming SLIP packets -- trivial operation since there's no * link level header */ slip_recv(interface,bp) struct interface *interface; struct mbuf *bp; { #ifdef TRACE if(trace & TRACE_SLIP){ printf("%s recv:\r\n",interface->name); if((trace & TRACE_HDR) > 2) ip_dump(bp); if(trace & TRACE_DUMP) hexdump(bp); if(trace & TRACE_ASCII) asciidump(bp); fflush(stdout); } #endif ip_route(bp,0); } /* Attach a serial interface to the system * argv[0]: hardware type, must be "asy" * argv[1]: I/O address, e.g., "0x3f8" * argv[2]: vector, e.g., "4" * argv[3]: mode, may be: * "slip" (point-to-point SLIP) * "ax25" (AX.25 UI frame format in SLIP for raw TNC) * argv[4]: interface label, e.g., "sl0" * argv[5]: receiver ring buffer size in bytes * argv[6]: maximum transmission unit, bytes * argv[7]: interface speed, e.g, "9600" */ asy_attach(argc,argv) int argc; char *argv[]; { register struct interface *if_asy; extern struct interface *ifaces; int dev; char *malloc(), *calloc(); int asy_init(); int asy_send(); int doslip(); int asy_stop(); int ax_send(); int kiss_recv(); int kiss_output(); if(nasy >= ASY_MAX){ printf("Too many asynch controllers\r\n"); return -1; } dev = nasy++; /* Initialize hardware-level control structure */ asy[dev].addr = htoi(argv[1]); asy[dev].vec = htoi(argv[2]); /* Create interface structure and fill in details */ if_asy = (struct interface *)calloc(1, sizeof(struct interface)); if_asy->name = malloc(strlen(argv[4])+1); strcpy(if_asy->name,argv[4]); if_asy->mtu = atoi(argv[6]); if_asy->dev = dev; if_asy->recv = doslip; if_asy->stop = asy_stop; if(strcmp(argv[3],"slip") == 0){ if_asy->send = slip_send; if_asy->output = NULLFP; if_asy->flags = 0; slip[dev].recv = slip_recv; } else if(strcmp(argv[3],"ax25") == 0){ if_asy->send = ax_send; if_asy->output = kiss_output; if_asy->flags = IF_BROADCAST; if(if_asy->hwaddr == NULLCHAR) if_asy->hwaddr = malloc(AXALEN); bcopy((char *)&mycall,if_asy->hwaddr,AXALEN); slip[dev].recv = kiss_recv; } else { printf("Mode %s unknown for interface %s\r\n", argv[3],argv[4]); free((char *)if_asy); return -1; } if_asy->next = ifaces; ifaces = if_asy; asy_init(dev,(unsigned)atoi(argv[5])); asy_speed(dev,atoi(argv[7])); }