/* SLIP (Serial Line IP) encapsulation and control routines. * Copyright 1991 Phil Karn * * Van Jacobsen header compression hooks added by Katie Stevens, UC Davis * * - Feb 1991 Bill_Simpson@um.cc.umich.edu * reflect changes to header compression calls * revise status display */ #include #include "global.h" #include "mbuf.h" #include "iface.h" #include "ip.h" #include "slhc.h" #include "asy.h" #include "slip.h" #include "trace.h" #include "pktdrvr.h" static struct mbuf *slip_decode __ARGS((struct slip *sp,char c)); static struct mbuf *slip_encode __ARGS((struct mbuf *bp)); /* Slip level control structure */ struct slip Slip[SLIP_MAX]; int slip_init(ifp,vj) struct iface *ifp; int vj; { int xdev; struct slip *sp; char *ifn; for(xdev = 0;xdev < SLIP_MAX;xdev++){ sp = &Slip[xdev]; if(sp->iface == NULLIF) break; } if(xdev >= SLIP_MAX) { tprintf("Too many slip devices\n"); return -1; } setencap(ifp,"SLIP"); ifp->ioctl = asy_ioctl; ifp->raw = slip_raw; ifp->show = slip_status; ifp->flags = 0; ifp->xdev = xdev; sp->iface = ifp; sp->send = asy_send; sp->get = get_asy; sp->type = CL_SERIAL_LINE; if(vj){ sp->escaped |= SLIP_VJCOMPR; sp->slcomp = slhc_init(16,16); } ifp->rxproc = newproc( ifn = if_name( ifp, " rx" ), 256,asy_rx,xdev,NULL,NULL,0); free(ifn); return 0; } int slip_free(ifp) struct iface *ifp; { struct slip *sp; sp = &Slip[ifp->xdev]; if(sp->slcomp != NULLSLCOMPR){ slhc_free(sp->slcomp); sp->slcomp = NULLSLCOMPR; } sp->iface = NULLIF; return 0; } /* Send routine for point-to-point slip */ int slip_send(bp,iface,gateway,tos) struct mbuf *bp; /* Buffer to send */ struct iface *iface; /* Pointer to interface control block */ int32 gateway; /* Ignored (SLIP is point-to-point) */ int tos; { register struct slip *sp; int type; if(iface == NULLIF){ free_p(bp); return -1; } sp = &Slip[iface->xdev]; if (sp->escaped & SLIP_VJCOMPR) { /* Attempt IP/ICP header compression */ type = slhc_compress(sp->slcomp,&bp,TRUE); bp->data[0] |= type; } return (*iface->raw)(iface,bp); } /* Send a raw slip frame */ int slip_raw(iface,bp) struct iface *iface; struct mbuf *bp; { struct mbuf *bp1; dump(iface,IF_TRACE_OUT,Slip[iface->xdev].type,bp); iface->rawsndcnt++; iface->lastsent = secclock(); if((bp1 = slip_encode(bp)) == NULLBUF){ return -1; } if (iface->trace & IF_TRACE_RAW) raw_dump(iface,-1,bp1); return Slip[iface->xdev].send(iface->dev,bp1); } /* 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; int 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((int16)(2*len_p(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((c = PULLCHAR(&bp)) != -1){ switch(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(sp,c) register struct slip *sp; char c; /* Incoming character */ { struct mbuf *bp; switch(uchar(c)){ case FR_END: bp = sp->rbp_head; sp->rbp_head = NULLBUF; return bp; /* Will be NULLBUF if empty frame */ case FR_ESC: sp->escaped |= SLIP_FLAG; return NULLBUF; } if(sp->escaped & SLIP_FLAG){ /* Translate 2-char escape sequence back to original char */ sp->escaped &= ~SLIP_FLAG; switch(uchar(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_head == NULLBUF){ /* Allocate first mbuf for new packet */ if((sp->rbp_tail = sp->rbp_head = alloc_mbuf(SLIP_ALLOC)) == NULLBUF) return NULLBUF; /* No memory, drop */ sp->rcp = sp->rbp_head->data; } else if(sp->rbp_tail->cnt == SLIP_ALLOC){ /* Current mbuf is full; link in another */ if((sp->rbp_tail->next = alloc_mbuf(SLIP_ALLOC)) == NULLBUF){ /* No memory, drop whole thing */ free_p(sp->rbp_head); sp->rbp_head = NULLBUF; return NULLBUF; } sp->rbp_tail = sp->rbp_tail->next; sp->rcp = sp->rbp_tail->data; } /* Store the character, increment fragment and total * byte counts */ *sp->rcp++ = c; sp->rbp_tail->cnt++; return NULLBUF; } /* Process SLIP line input */ void asy_rx(xdev,p1,p2) int xdev; void *p1; void *p2; { int c; struct mbuf *bp; register struct slip *sp; int cdev; sp = &Slip[xdev]; cdev = sp->iface->dev; while ( (c = sp->get(cdev)) != -1 ) { if((bp = slip_decode(sp,(char)c)) == NULLBUF) continue; /* More to come */ if (sp->iface->trace & IF_TRACE_RAW) raw_dump(sp->iface,IF_TRACE_IN,bp); if (sp->escaped & SLIP_VJCOMPR) { if ((c = bp->data[0]) & SL_TYPE_COMPRESSED_TCP) { if ( slhc_uncompress(sp->slcomp, &bp) <= 0 ) { free_p(bp); sp->errors++; continue; } } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { bp->data[0] &= 0x4f; if ( slhc_remember(sp->slcomp, &bp) <= 0 ) { free_p(bp); sp->errors++; continue; } } } net_route( sp->iface, sp->type, bp ); /* Especially on slow machines, serial I/O can be quite * compute intensive, so release the machine before we * do the next packet. This will allow this packet to * go on toward its ultimate destination. [Karn] */ pwait(NULL); } free_p(bp); } /* Show serial line status */ void slip_status(iface) struct iface *iface; { struct slip *sp; if (iface->xdev > SLIP_MAX) /* Must not be a SLIP device */ return; sp = &Slip[iface->xdev]; if (sp->iface != iface) /* Must not be a SLIP device */ return; slhc_i_status(sp->slcomp); slhc_o_status(sp->slcomp); }