/* * stil - Internet link protocol */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #include "arp.h" #include "ipdat.h" #define DPRINT if(pip)print int ilcksum = 1; Queue *Iloutput; /* Il to lance output channel */ void ilrcvmsg(Ipconv*, Block*); void ilackproc(void*); void ilopen(Queue *q, Stream *s) { Ipconv *ipc; /* Start il service processes */ if(!Iloutput) { Iloutput = WR(q); /* This never goes away - we use this queue to send acks/rejects */ s->opens++; s->inuse++; kproc("ilack", ilackproc, 0); } ipc = &ipconv[s->dev][s->id]; ipc->ipinterface = newipifc(IP_ILPROTO, ilrcvmsg, ipconv[s->dev], 1500, 512, ETHER_HDR, "IL"); qlock(ipc); ipc->ref++; qunlock(ipc); ipc->readq = RD(q); RD(q)->ptr = (void *)ipc; WR(q)->next->ptr = (void *)ipc->ipinterface; WR(q)->ptr = (void *)ipc; } void ilclose(Queue *q) { } void iloput(Queue *q, Block *bp) { Ipconv *ipc; Ilhdr *ih; Ilcb *ic; int dlen; Block *np; /* Prepend udp header to packet and pass on to ip layer */ ipc = (Ipconv *)(q->ptr); if(ipc->psrc == 0) error(Enoport); if(bp->type != M_DATA) { freeb(bp); error(Ebadctl); } /* Only allow atomic Il writes to form datagrams */ if(!(bp->flags & S_DELIM)) { freeb(bp); error(Emsgsize); } dlen = blen(bp); if(dlen > IL_DATMAX) { freeb(bp); error(Emsgsize); } /* Make space to fit il & ip & ethernet header */ bp = padb(bp, IL_EHSIZE+IL_HDRSIZE); ih = (Ilhdr *)(bp->rptr); ic = &ipc->ilctl; hnputs(ih->illen, dlen+IL_EHSIZE+IL_HDRSIZE); hnputs(ih->ilsrc, ipc->psrc); hnputs(ih->ildst, ipc->pdst); ih->iltype = Ildata; ih->ilspec = 0; hnputl(ih->ilid, ic->sent++); hnputl(ih->ilack, ic->recvd); ih->ilsum[0] = 0; ih->ilsum[1] = 0; /* Checksum of ilheader plus data (not ip & no pseudo header) */ if(ilcksum) hnputs(ih->ilsum, ptcl_csum(bp, IL_EHSIZE, dlen+IL_HDRSIZE)); /* Enqueue a copy on the unacked queue in case this one gets lost */ np = copyb(bp, blen(bp)); if(ic->unacked) { ic->unackedtail->next = np; ic->unackedtail = np; } else { ic->unacked = np; ic->unackedtail = np; } np->next = 0; PUTNEXT(q, bp); } void iliput(Queue *q, Block *bp) { PUTNEXT(q, bp); } void ilrcvmsg(Ipconv *ipc, Block *bp) { Ilhdr *ih; ih = (Ilhdr *)bp; plen = blen(bp); if(plen < IL_EHSIZE+IL_HDRSIZE) goto drop; if(ilcksum && ptcl_csum(bp, IL_EHSIZE, plen) != 0) { print("il: cksum error\n"); goto drop; } s = ip_conn(ipc, hngets(ih->ildst), hngets(ih->ilsrc), hngetl(), IP_ILPROTO); if(s == 0) { ilsentctl(0, ih, Ilreset); goto drop; } switch(s->state) { case Closed: ilsentctl(0, ih, Ilreset); goto drop; case Syncee: case Syncer: case Established: case Closing: } drop: freeb(bp); } void ilsendctl(Ipconv *ipc, Ilhdr *inih, int type) { Ilhdr *ih; Ilcb *ic; Block *bp; bp = allocb(IL_EHSIZE+IL_HDRSIZE); ih = (Ilhdr *)(bp->rptr); ic = &ipc->ilctl; hnputs(ih->illen, IL_EHSIZE+IL_HDRSIZE); if(inih) { hnputs(ih->ilsrc, inih->ildst); hnputs(ih->ildst, inih->ilsrc); hnputl(ih->ilid, inih->recvd); hnputl(ih->ilack, inih->sent); } else { hnputs(ih->ilsrc, ipc->psrc); hnputs(ih->ildst, ipc->pdst); hnputl(ih->ilid, ic->sent); hnputl(ih->ilack, ic->recvd); } ih->iltype = type; ih->ilspec = 0; ih->ilsum[0] = 0; ih->ilsum[1] = 0; if(ilcksum) hnputs(ih->ilsum, ptcl_csum(bp, IL_EHSIZE, IL_HDRSIZE)); PUTNEXT(Iloutput, bp); } void ilackproc(void *junk) { }