/* Send and receive IP datagrams on serial lines. Compatible with SLIP * under Berkeley Unix. */ #include #include "config.h" #include "global.h" #include "mbuf.h" #include "iface.h" #include "timer.h" #ifdef SLFP #include "ip.h" #include "slfp.h" #endif #include "ax25.h" #include "slip.h" #include "nrs.h" #ifdef UNIX /* BSD or SYS5 */ #include "unix.h" #else # ifdef ATARI_ST # include "st.h" # else # include "pc.h" # include "asy.h" # endif /* ATARI_ST */ #endif /* BSD or SYS5 */ #include "trace.h" int asy_ioctl(); int kiss_ioctl(); int slip_send(); int doslip(); int asy_output(); #ifdef SLFP int doslfp(); int slfp_raw(); int slfp_send(); int slfp_recv(); int slfp_init(); #endif /* Slip level control structure */ struct slip slip[ASY_MAX]; /* 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; { if(interface == NULLIF){ free_p(bp); return; } dump(interface,IF_TRACE_OUT,TRACE_IP,bp); (*interface->raw)(interface,bp); } /* Send a raw slip frame -- also trivial */ slip_raw(interface,bp) struct interface *interface; struct mbuf *bp; { /* Queue a frame on the slip output queue and start transmitter */ slipq(interface->dev,bp); } /* Encode a raw packet in slip framing, put on link output queue, and kick * transmitter */ static 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) int16 dev; /* Slip unit number */ char c; /* Incoming character */ { struct mbuf *bp; register struct slip *sp; sp = &slip[dev]; switch(c & 0xff){ case FR_END: bp = sp->rbp; sp->rbp = NULLBUF; sp->rcnt = 0; return bp; /* Will be NULLBUF if empty frame */ 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++; break; /* DG2KK: from .16 */ } } /* 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; int16 asy_recv(); 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; { void ip_route(); /* By definition, all incoming packets are "addressed" to us */ dump(interface,IF_TRACE_IN,TRACE_IP,bp); 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 frame format in SLIP for raw TNC) * "slfp" (point-to-point SL/FP, as used by the Merit Network and MIT) * "nrs" (net/rom to net/rom serial framing method) * 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" * argv[8]: optional, may be: * ax.25 callsign DG2KK: new from netrom version * command string to MODEM, e.g. ATDT */ asy_attach(argc,argv) int argc; char *argv[]; { register struct interface *if_asy; extern struct interface *ifaces; int16 dev; char *call; /* DG2KK: new from netrom version */ int mode; /* " */ int asy_init(); int asy_send(); int doslip(); int asy_stop(); int ax_send(); int ax_output(); int kiss_recv(); int kiss_raw(); if(nasy >= ASY_MAX){ printf("Too many asynch controllers\n"); return -1; } if(strcmp(argv[3],"slip") == 0) mode = SLIP_MODE; #ifdef SLFP else if(strcmp(argv[3],"slfp") == 0) mode = SLFP_MODE; #endif else if(strcmp(argv[3],"ax25") == 0) mode = AX25_MODE; #ifdef NRS else if(strcmp(argv[3],"nrs") == 0) mode = NRS_MODE; #endif else { printf("Mode %s unknown for interface %s\n", argv[3],argv[4]); return -1; } dev = nasy++; #ifdef UNIX /* BSD or SYS5 */ asy[dev].tty = malloc(strlen(argv[2])+1); strcpy(asy[dev].tty, argv[2]); #else #ifndef ATARI_ST /* Initialize hardware-level control structure */ asy[dev].addr = htoi(argv[1]); asy[dev].vec = htoi(argv[2]); #else /* -------- this is Atari-ST specific ---------(DG2KK)---------------------- */ /* argv[1] (COM Port address) is the Atari device name * (either "AUX:" or "MIDI") * argv[2] (Interrupt vector) is used as a flag to indicate if * bytes received on that interface should be sent out on * another interface (1 = AUX: 3 = MIDI). */ asy[dev].vec = atoi(argv[2]); /* dev to resend bytes to */ asy[dev].addr = 0; /* use as error flag */ if (strcmp(argv[1],"AUX:") == 0) { asy[dev].addr = 1; /* don't allow retransmission on AUX: if mode is ax25! */ if (strcmp(argv[3],"ax25") == 0 && asy[dev].vec == 1) { asy[dev].vec = 0; } } if (strcmp(argv[1],"MIDI") == 0) { asy[dev].addr = 3; } if (strcmp(argv[1],"CON:") == 0) { /* this is pretty silly ! */ asy[dev].addr = 2; } if (asy[dev].addr == 0) { return -1; } /* ---------- end of Atari-specific stuff ------------------------------ */ #endif /* ATARI_ST */ #endif /* BSD or SYS5 */ /* Create interface structure and fill in details */ if_asy = (struct interface *)calloc(1,sizeof(struct interface)); if_asy->name = malloc((unsigned)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 (argc == 9) call = argv[8]; else call = NULLCHAR; switch(mode){ case SLIP_MODE: if_asy->ioctl = asy_ioctl; if_asy->send = slip_send; if_asy->output = NULLFP; /* ARP isn't used */ if_asy->raw = slip_raw; if_asy->flags = 0; slip[dev].recv = slip_recv; break; #ifdef AX25 case AX25_MODE: /* This function is done in main.c so it can be easily * ifdef'ed out */ if(kiss_attach(if_asy,&slip[dev].recv) == -1){ free(if_asy->name); free((char *)if_asy); nasy--; return -1; } break; #endif #ifdef NRS case NRS_MODE: if (nrs_attach(if_asy,call) == -1) { free(if_asy->name); free((char *)if_asy); nasy--; return -1; } nrs[dev].iface = if_asy; break; #endif #ifdef SLFP case SLFP_MODE: if_asy->ioctl = asy_ioctl; if_asy->send = slfp_send; if_asy->recv = doslfp; if_asy->output = NULLFP; /* ARP isn't used */ if_asy->raw = slfp_raw; if_asy->flags = 0; slfp[dev].recv = slfp_recv; break; #endif } if_asy->next = ifaces; ifaces = if_asy; asy_init(dev,(unsigned)atoi(argv[5])); asy_speed(dev,atoi(argv[7])); #ifdef SLFP if(mode == SLFP_MODE) if(slfp_init(if_asy, &ip_addr, argc>7?argv[8]:NULLCHAR) == -1) { printf("Request for IP address timed out.\n"); asy_stop(if_asy); ifaces = if_asy->next; free((char *)if_asy); return -1; } #endif return 0; }