| plan 9 kernel history: overview | file list | diff list |
1992/0717/port/devip.c (diff list | history)
| port/devip.c on 1991/0424 | ||
| 1991/0424 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1991/0424 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0424 | #include "arp.h" #include "ipdat.h" #include "devtab.h" | |
| 1991/1012 | enum { | |
| 1992/0318 | Nrprotocol = 3, /* Number of protocols supported by this driver */ Nipsubdir = 4, /* Number of subdirectory entries per connection */ | |
| 1992/0626 | Nfrag = 32, /* Ip reassembly queue entries */ Nifc = 4, /* max interfaces */ | |
| 1991/0424 | }; | |
| 1991/1030 | int udpsum = 1; | |
| 1991/12171 | Queue *Ipoutput; /* Control message stream for tcp/il */ | |
| 1992/0626 | Ipifc *ipifc[Nrprotocol+1]; | |
| 1991/12171 | QLock ipalloc; /* Protocol port allocation lock */ | |
| 1992/0626 | Ipconv **tcpbase; | |
| 1991/0424 | ||
| 1992/0625 | Streamput udpstiput, udpstoput, tcpstiput, tcpstoput, iliput, iloput, bsdiput, bsdoput; Streamopen udpstopen, tcpstopen, ilopen, bsdopen; Streamclose udpstclose, tcpstclose, ilclose, bsdclose; | |
| 1991/0424 | ||
| 1992/0318 | Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 }; | |
| 1991/0424 | Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" }; | |
| 1991/1012 | Qinfo ilinfo = { iliput, iloput, ilopen, ilclose, "il" }; | |
| 1992/0529 | Qinfo bsdinfo = { bsdiput, bsdoput, bsdopen, bsdclose, "bsd", 0, 1 }; | |
| 1991/0424 | ||
| 1991/1012 | Qinfo *protocols[] = { &tcpinfo, &udpinfo, &ilinfo, 0 }; | |
| 1991/0424 | ||
| 1991/1114 | void | |
| 1992/0626 | ipinitifc(Ipifc *ifc, Qinfo *stproto) | |
| 1991/1012 | { | |
| 1992/0626 | ifc->conv = xalloc(Nipconv * sizeof(Ipconv*)); ifc->protop = stproto; ifc->nconv = Nipconv; ifc->devp = &ipinfo; | |
| 1991/1114 | if(stproto != &udpinfo) | |
| 1992/0626 | ifc->listen = iplisten; ifc->clone = ipclonecon; ifc->ninfo = 3; ifc->info[0].name = "remote"; ifc->info[0].fill = ipremotefill; ifc->info[1].name = "local"; ifc->info[1].fill = iplocalfill; ifc->info[2].name = "status"; ifc->info[2].fill = ipstatusfill; ifc->name = stproto->name; | |
| 1991/1114 | } | |
| 1991/0424 | void ipreset(void) { | |
| 1992/0626 | int i; | |
| 1991/0424 | ||
| 1991/1012 | for(i = 0; protocols[i]; i++) { | |
| 1992/0626 | ipifc[i] = xalloc(sizeof(Ipifc)); ipinitifc(ipifc[i], protocols[i]); | |
| 1991/0424 | newqinfo(protocols[i]); } | |
| 1992/0626 | initfrag(Nfrag); | |
| 1991/0424 | } void ipinit(void) { } Chan * ipattach(char *spec) { Chan *c; int i; | |
| 1992/0219 | /* fail if ip is not yet configured */ if(Ipoutput == 0) error(Enoproto); | |
| 1991/0424 | for(i = 0; protocols[i]; i++) { if(strcmp(spec, protocols[i]->name) == 0) { c = devattach('I', spec); c->dev = i; return (c); } } error(Enoproto); | |
| 1992/0520 | return 0; /* not reached */ | |
| 1991/0424 | } Chan * ipclone(Chan *c, Chan *nc) { return devclone(c, nc); } int ipwalk(Chan *c, char *name) { | |
| 1992/0626 | return netwalk(c, name, ipifc[c->dev]); | |
| 1991/0424 | } void ipstat(Chan *c, char *db) { | |
| 1992/0626 | netstat(c, db, ipifc[c->dev]); | |
| 1991/0424 | } Chan * ipopen(Chan *c, int omode) { | |
| 1992/0626 | return netopen(c, omode, ipifc[c->dev]); | |
| 1991/0424 | } | |
| 1991/1114 | int | |
| 1991/0424 | ipclonecon(Chan *c) { | |
| 1992/0626 | Ipconv *new; | |
| 1991/0424 | ||
| 1992/0626 | new = ipincoming(ipifc[c->dev], 0); | |
| 1991/1108 | if(new == 0) error(Enodev); | |
| 1992/0626 | return new->id; | |
| 1991/1023 | } | |
| 1992/0626 | /* * create a new conversation structure if none exists for this conversation slot */ Ipconv* ipcreateconv(Ipifc *ifc, int id) | |
| 1991/1023 | { | |
| 1992/0626 | Ipconv **p; Ipconv *new; | |
| 1991/1023 | ||
| 1992/0626 | p = &ifc->conv[id]; if(*p) return *p; qlock(ifc); p = &ifc->conv[id]; if(*p){ qunlock(ifc); return *p; } if(waserror()){ qunlock(ifc); nexterror(); } new = smalloc(sizeof(Ipconv)); new->ifc = ifc; netadd(ifc, new, p - ifc->conv); new->ref = 1; *p = new; qunlock(ifc); poperror(); return new; } /* * allocate a conversation structure. */ Ipconv* ipincoming(Ipifc *ifc, Ipconv *from) { Ipconv **p, **etab; Ipconv *new; /* look for an unused existing conversation */ etab = &ifc->conv[Nipconv]; for(p = ifc->conv; p < etab; p++) { new = *p; if(new == 0) break; | |
| 1991/0424 | if(new->ref == 0 && canqlock(new)) { | |
| 1992/0313 | if(new->ref || ipconbusy(new)) { | |
| 1991/0424 | qunlock(new); continue; } | |
| 1992/0318 | if(from) /* copy ownership from listening channel */ | |
| 1992/0623 | netown(new, from->owner, 0); | |
| 1992/0318 | else /* current user becomes owner */ | |
| 1992/0623 | netown(new, u->p->user, 0); | |
| 1992/0313 | ||
| 1991/1114 | new->ref = 1; | |
| 1991/0424 | qunlock(new); return new; } } | |
| 1992/0626 | /* create one */ qlock(ifc); etab = &ifc->conv[Nipconv]; for(p = ifc->conv; ; p++){ if(p == etab){ qunlock(ifc); return 0; } if(*p == 0) break; } if(waserror()){ qunlock(ifc); nexterror(); } new = smalloc(sizeof(Ipconv)); new->ifc = ifc; netadd(ifc, new, p - ifc->conv); qlock(new); *p = new; qunlock(ifc); if(from) /* copy ownership from listening channel */ netown(new, from->owner, 0); else /* current user becomes owner */ netown(new, u->p->user, 0); new->ref = 1; qunlock(new); return new; | |
| 1991/0424 | } void ipcreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1115 | USED(c, name, omode, perm); | |
| 1991/0424 | error(Eperm); } void ipremove(Chan *c) { | |
| 1991/1115 | USED(c); | |
| 1991/0424 | error(Eperm); } void ipwstat(Chan *c, char *dp) { | |
| 1992/0626 | netwstat(c, dp, ipifc[c->dev]); | |
| 1991/0424 | } void ipclose(Chan *c) { | |
| 1991/1114 | if(c->stream) | |
| 1991/0424 | streamclose(c); } long ipread(Chan *c, void *a, long n, ulong offset) { | |
| 1992/0626 | return netread(c, a, n, offset, ipifc[c->dev]); | |
| 1991/0424 | } long ipwrite(Chan *c, char *a, long n, ulong offset) { | |
| 1992/0128 | int m, backlog, type, priv; | |
| 1991/1024 | char *field[5], *ctlarg[5], buf[256]; | |
| 1992/0128 | Port port; | |
| 1991/1024 | Ipconv *cp; | |
| 1991/0424 | ||
| 1992/0711 | USED(offset); | |
| 1991/0424 | type = STREAMTYPE(c->qid.path); if (type == Sdataqid) return streamwrite(c, a, n, 0); | |
| 1991/1024 | if (type != Sctlqid) error(Eperm); | |
| 1991/0424 | ||
| 1992/0626 | cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); | |
| 1991/0424 | ||
| 1991/1024 | m = n; if(m > sizeof(buf)-1) m = sizeof(buf)-1; strncpy(buf, a, m); buf[m] = '\0'; | |
| 1991/0516 | ||
| 1991/1024 | m = getfields(buf, field, 5, ' '); if(m < 1) | |
| 1992/0111 | error(Ebadarg); | |
| 1991/0424 | ||
| 1991/1024 | if(strcmp(field[0], "connect") == 0) { | |
| 1992/0313 | if(ipconbusy(cp)) error(Enetbusy); | |
| 1991/0424 | ||
| 1991/1024 | if(m != 2) error(Ebadarg); | |
| 1991/0424 | ||
| 1991/1025 | switch(getfields(field[1], ctlarg, 5, '!')) { | |
| 1991/1024 | default: | |
| 1992/0528 | error(Eneedservice); | |
| 1991/1024 | case 2: | |
| 1992/0128 | priv = 0; | |
| 1991/1024 | break; case 3: if(strcmp(ctlarg[2], "r") != 0) error(Eperm); | |
| 1992/0128 | priv = 1; | |
| 1991/1024 | break; | |
| 1991/0424 | } | |
| 1991/1024 | cp->dst = ipparse(ctlarg[0]); cp->pdst = atoi(ctlarg[1]); | |
| 1991/0516 | ||
| 1991/1024 | /* If we have no local port assign one */ | |
| 1992/0416 | if(cp->psrc == 0){ qlock(&ipalloc); | |
| 1992/0626 | cp->psrc = nextport(ipifc[c->dev], priv); | |
| 1992/0416 | qunlock(&ipalloc); } | |
| 1991/0424 | ||
| 1992/0626 | if(cp->ifc->protop == &tcpinfo) | |
| 1991/1114 | tcpstart(cp, TCP_ACTIVE, Streamhi, 0); | |
| 1992/0626 | else if(cp->ifc->protop == &ilinfo) | |
| 1991/1124 | ilstart(cp, IL_ACTIVE, 20); | |
| 1991/1114 | ||
| 1992/0529 | /* * stupid hack for BSD port's 512, 513, & 514 * to make it harder for user to lie about his * identity. -- presotto */ switch(cp->pdst){ case 512: case 513: case 514: pushq(c->stream, &bsdinfo); break; } | |
| 1991/1024 | } | |
| 1991/1125 | else if(strcmp(field[0], "disconnect") == 0) { | |
| 1992/0626 | if(cp->ifc->protop != &udpinfo) | |
| 1991/1125 | error(Eperm); cp->dst = 0; cp->pdst = 0; } | |
| 1991/1104 | else if(strcmp(field[0], "announce") == 0) { | |
| 1992/0313 | if(ipconbusy(cp)) error(Enetbusy); | |
| 1991/0424 | ||
| 1991/1024 | if(m != 2) error(Ebadarg); port = atoi(field[1]); | |
| 1992/0416 | if(port){ qlock(&ipalloc); | |
| 1992/0626 | if(portused(ipifc[c->dev], port)) { | |
| 1992/0416 | qunlock(&ipalloc); error(Einuse); } cp->psrc = port; qunlock(&ipalloc); } else if(*field[1] != '*'){ qlock(&ipalloc); | |
| 1992/0626 | cp->psrc = nextport(ipifc[c->dev], 0); | |
| 1992/0416 | qunlock(&ipalloc); } else cp->psrc = 0; | |
| 1991/1114 | ||
| 1992/0626 | if(cp->ifc->protop == &tcpinfo) | |
| 1991/1114 | tcpstart(cp, TCP_PASSIVE, Streamhi, 0); | |
| 1992/0626 | else if(cp->ifc->protop == &ilinfo) | |
| 1991/1114 | ilstart(cp, IL_PASSIVE, 10); if(cp->backlog == 0) cp->backlog = 3; | |
| 1991/0424 | } | |
| 1991/1024 | else if(strcmp(field[0], "backlog") == 0) { if(m != 2) error(Ebadarg); backlog = atoi(field[1]); if(backlog == 0) error(Ebadarg); if(backlog > 5) backlog = 5; cp->backlog = backlog; } | |
| 1992/0627 | else if(strcmp(field[0], "headers") == 0) { cp->headers = 1; /* include addr/port in user packet */ } | |
| 1991/1024 | else return streamwrite(c, a, n, 0); | |
| 1991/0424 | ||
| 1991/1024 | return n; | |
| 1991/0424 | } | |
| 1992/0313 | int ipconbusy(Ipconv *cp) { | |
| 1992/0626 | if(cp->ifc->protop == &tcpinfo) | |
| 1992/0313 | if(cp->tcpctl.state != Closed) return 1; | |
| 1991/0424 | ||
| 1992/0626 | if(cp->ifc->protop == &ilinfo) | |
| 1992/0313 | if(cp->ilctl.state != Ilclosed) return 1; return 0; } | |
| 1991/0424 | void udpstiput(Queue *q, Block *bp) { | |
| 1991/0516 | PUTNEXT(q, bp); | |
| 1991/0424 | } /* * udprcvmsg - called by stip to multiplex udp ports onto conversations */ void | |
| 1992/0626 | udprcvmsg(Ipifc *ifc, Block *bp) | |
| 1991/0424 | { | |
| 1992/0626 | Ipconv *cp, **p, **etab; | |
| 1991/0424 | Udphdr *uh; | |
| 1991/1125 | Port dport, sport; | |
| 1991/0424 | ushort sum, len; Ipaddr addr; | |
| 1992/0627 | Block *nbp; | |
| 1991/0424 | uh = (Udphdr *)(bp->rptr); /* Put back pseudo header for checksum */ uh->Unused = 0; len = nhgets(uh->udplen); hnputs(uh->udpplen, len); addr = nhgetl(uh->udpsrc); if(udpsum && nhgets(uh->udpcksum)) { if(sum = ptcl_csum(bp, UDP_EHSIZE, len+UDP_PHDRSIZE)) { print("udp: checksum error %x (%d.%d.%d.%d)\n", sum, fmtaddr(addr)); freeb(bp); return; } } dport = nhgets(uh->udpdport); | |
| 1991/1125 | sport = nhgets(uh->udpsport); | |
| 1991/0424 | /* Look for a conversation structure for this port */ | |
| 1992/0626 | etab = &ifc->conv[Nipconv]; for(p = ifc->conv; p < etab; p++) { cp = *p; if(cp == 0) break; if(cp->ref) if(cp->psrc == dport) if(cp->pdst == 0 || cp->pdst == sport) { | |
| 1991/0424 | /* Trim the packet down to data size */ len = len - (UDP_HDRSIZE-UDP_PHDRSIZE); bp = btrim(bp, UDP_EHSIZE+UDP_HDRSIZE, len); if(bp == 0) return; | |
| 1992/0627 | if(cp->headers){ /* pass the src address to the stream head */ nbp = allocb(Udphdrsize); nbp->next = bp; bp = nbp; hnputl(bp->wptr, addr); bp->wptr += 4; hnputs(bp->wptr, sport); bp->wptr += 2; } else { /* save the src address in the conversation struct */ cp->dst = addr; cp->pdst = sport; } | |
| 1992/0626 | PUTNEXT(cp->readq, bp); | |
| 1991/0424 | return; } } freeb(bp); } void udpstoput(Queue *q, Block *bp) { | |
| 1992/0627 | Ipconv *cp; | |
| 1991/0424 | Udphdr *uh; | |
| 1991/1104 | int dlen, ptcllen, newlen; | |
| 1992/0627 | Ipaddr addr; Port port; | |
| 1991/0424 | ||
| 1991/1104 | if(bp->type == M_CTL) { PUTNEXT(q, bp); return; } | |
| 1992/0627 | cp = (Ipconv *)(q->ptr); if(cp->psrc == 0) | |
| 1991/0424 | error(Enoport); if(bp->type != M_DATA) { freeb(bp); error(Ebadctl); } /* Only allow atomic udp writes to form datagrams */ if(!(bp->flags & S_DELIM)) { freeb(bp); error(Emsgsize); } | |
| 1992/0627 | /* * if we're in header mode, rip off the first 64 bytes as the * destination. The destination is in ascii in the form * %d.%d.%d.%d!%d */ if(cp->headers){ /* get user specified addresses */ bp = pullup(bp, Udphdrsize); if(bp == 0){ freeb(bp); error(Emsgsize); } addr = nhgetl(bp->rptr); bp->rptr += 4; port = nhgets(bp->rptr); bp->rptr += 2; } else addr = port = 0; | |
| 1991/0424 | /* Round packet up to even number of bytes and check we can * send it */ dlen = blen(bp); if(dlen > UDP_DATMAX) { freeb(bp); error(Emsgsize); } newlen = bround(bp, 1); /* Make space to fit udp & ip & ethernet header */ bp = padb(bp, UDP_EHSIZE + UDP_HDRSIZE); uh = (Udphdr *)(bp->rptr); ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; | |
| 1992/0106 | uh->frag[0] = 0; uh->frag[1] = 0; | |
| 1991/0424 | hnputs(uh->udpplen, ptcllen); | |
| 1992/0213 | hnputl(uh->udpsrc, Myip[Myself]); | |
| 1992/0627 | hnputs(uh->udpsport, cp->psrc); if(cp->headers){ hnputl(uh->udpdst, addr); hnputs(uh->udpdport, port); } else { hnputl(uh->udpdst, cp->dst); hnputs(uh->udpdport, cp->pdst); } | |
| 1991/0424 | hnputs(uh->udplen, ptcllen); uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; hnputs(uh->udpcksum, ptcl_csum(bp, UDP_EHSIZE, newlen+UDP_HDRSIZE)); PUTNEXT(q, bp); } void udpstclose(Queue *q) { Ipconv *ipc; ipc = (Ipconv *)(q->ptr); | |
| 1992/0627 | ipc->headers = 0; | |
| 1991/1114 | ipc->psrc = 0; ipc->pdst = 0; ipc->dst = 0; | |
| 1991/0424 | } void udpstopen(Queue *q, Stream *s) { Ipconv *ipc; | |
| 1992/0626 | ipc = ipcreateconv(ipifc[s->dev], s->id); | |
| 1992/0711 | initipifc(ipifc[s->dev], IP_UDPPROTO, udprcvmsg, 1500, 512, ETHER_HDR); | |
| 1991/0424 | ipc->readq = RD(q); RD(q)->ptr = (void *)ipc; | |
| 1992/0626 | WR(q)->next->ptr = (void *)ipc->ifc; | |
| 1991/0424 | WR(q)->ptr = (void *)ipc; } void tcpstiput(Queue *q, Block *bp) { | |
| 1991/0516 | PUTNEXT(q, bp); | |
| 1991/0424 | } void tcpstoput(Queue *q, Block *bp) { Ipconv *s; Tcpctl *tcb; | |
| 1991/1126 | Block *f; | |
| 1991/0424 | s = (Ipconv *)(q->ptr); tcb = &s->tcpctl; | |
| 1991/1104 | if(bp->type == M_CTL) { PUTNEXT(q, bp); return; } | |
| 1991/0424 | if(s->psrc == 0) error(Enoport); /* Report asynchronous errors */ if(s->err) error(s->err); switch(tcb->state) { | |
| 1991/12171 | case Listen: | |
| 1991/0424 | tcb->flags |= ACTIVE; send_syn(tcb); | |
| 1991/12171 | setstate(s, Syn_sent); | |
| 1992/0313 | ||
| 1991/0424 | /* No break */ | |
| 1991/12171 | case Syn_sent: case Syn_received: case Established: case Close_wait: | |
| 1991/0424 | qlock(tcb); | |
| 1992/0322 | if(waserror()) { qunlock(tcb); nexterror(); } | |
| 1991/1126 | tcb->sndcnt += blen(bp); if(tcb->sndq == 0) tcb->sndq = bp; else { for(f = tcb->sndq; f->next; f = f->next) ; f->next = bp; } | |
| 1991/0424 | tcprcvwin(s); tcp_output(s); | |
| 1992/0322 | poperror(); | |
| 1991/0424 | qunlock(tcb); break; | |
| 1992/0313 | ||
| 1991/0424 | default: freeb(bp); error(Ehungup); } } void tcpstopen(Queue *q, Stream *s) { Ipconv *ipc; | |
| 1992/0626 | Ipifc *ifc; | |
| 1992/0416 | Tcpctl *tcb; Block *bp; | |
| 1991/1019 | static int tcpkprocs; | |
| 1991/0424 | ||
| 1991/1019 | if(!Ipoutput) { Ipoutput = WR(q); | |
| 1991/0430 | s->opens++; | |
| 1991/0504 | s->inuse++; | |
| 1991/1019 | } /* Flow control and tcp timer processes */ if(tcpkprocs == 0) { tcpkprocs = 1; | |
| 1991/0424 | kproc("tcpack", tcpackproc, 0); | |
| 1992/0626 | kproc("tcpflow", tcpflow, ipifc[s->dev]); | |
| 1991/0430 | ||
| 1991/0424 | } | |
| 1992/0416 | if(tcpbase == 0) | |
| 1992/0626 | tcpbase = ipifc[s->dev]->conv; ifc = ipifc[s->dev]; | |
| 1992/0711 | initipifc(ifc, IP_TCPPROTO, tcp_input, 1500, 512, ETHER_HDR); | |
| 1992/0626 | ipc = ipcreateconv(ifc, s->id); | |
| 1991/0424 | ipc->readq = RD(q); ipc->readq->rp = &tcpflowr; | |
| 1992/0128 | ipc->err = 0; | |
| 1991/0424 | RD(q)->ptr = (void *)ipc; | |
| 1992/0626 | WR(q)->next->ptr = (void *)ipc->ifc; | |
| 1991/0424 | WR(q)->ptr = (void *)ipc; | |
| 1992/0416 | /* pass any waiting data upstream */ tcb = &ipc->tcpctl; qlock(tcb); while(bp = getb(&tcb->rcvq)) PUTNEXT(ipc->readq, bp); qunlock(tcb); | |
| 1991/0424 | } | |
| 1991/1114 | void ipremotefill(Chan *c, char *buf, int len) { Ipconv *cp; | |
| 1992/0711 | if(len < 24) error(Ebadarg); | |
| 1992/0626 | cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); | |
| 1992/0717 | sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(cp->dst), cp->pdst); | |
| 1991/1114 | } | |
| 1991/1124 | ||
| 1991/1114 | void iplocalfill(Chan *c, char *buf, int len) { Ipconv *cp; | |
| 1992/0711 | if(len < 24) error(Ebadarg); | |
| 1992/0626 | cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); | |
| 1992/0717 | sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(Myip[Myself]), cp->psrc); | |
| 1991/1114 | } | |
| 1991/1124 | ||
| 1991/1114 | void ipstatusfill(Chan *c, char *buf, int len) { int connection; Ipconv *cp; | |
| 1992/0711 | if(len < 64) error(Ebadarg); | |
| 1991/1114 | connection = STREAMID(c->qid.path); | |
| 1992/0626 | cp = ipcreateconv(ipifc[c->dev], connection); if(cp->ifc->protop == &tcpinfo) | |
| 1991/1114 | sprint(buf, "tcp/%d %d %s %s\n", connection, cp->ref, tcpstate[cp->tcpctl.state], cp->tcpctl.flags & CLONE ? "listen" : "connect"); | |
| 1992/0626 | else if(cp->ifc->protop == &ilinfo) | |
| 1992/0307 | sprint(buf, "il/%d %d %s rtt %d ms %d csum\n", connection, cp->ref, ilstate[cp->ilctl.state], cp->ilctl.rtt, | |
| 1992/0626 | cp->ifc ? cp->ifc->chkerrs : 0); | |
| 1991/1114 | else | |
| 1992/0626 | sprint(buf, "%s/%d %d\n", cp->ifc->protop->name, connection, cp->ref); | |
| 1991/1114 | } | |
| 1991/0424 | int | |
| 1991/1023 | iphavecon(Ipconv *s) | |
| 1991/0424 | { return s->curlog; } | |
| 1991/1114 | int iplisten(Chan *c) | |
| 1991/0424 | { | |
| 1992/0626 | Ipconv **p, **etab, *new; Ipconv *s; | |
| 1991/1114 | int connection; | |
| 1991/0424 | ||
| 1991/1114 | connection = STREAMID(c->qid.path); | |
| 1992/0626 | s = ipcreateconv(ipifc[c->dev], connection); | |
| 1991/1114 | ||
| 1992/0626 | if(s->ifc->protop == &tcpinfo) | |
| 1992/0313 | if(s->tcpctl.state != Listen) | |
| 1992/0112 | error(Enolisten); | |
| 1991/1114 | ||
| 1992/0626 | if(s->ifc->protop == &ilinfo) | |
| 1992/0313 | if(s->ilctl.state != Illistening) error(Enolisten); | |
| 1991/0424 | for(;;) { | |
| 1992/0414 | qlock(&s->listenq); /* single thread for the sleep */ if(waserror()) { qunlock(&s->listenq); nexterror(); } | |
| 1991/1023 | sleep(&s->listenr, iphavecon, s); | |
| 1991/1025 | poperror(); | |
| 1992/0626 | etab = &ipifc[c->dev]->conv[Nipconv]; for(p = ipifc[c->dev]->conv; p < etab; p++) { new = *p; if(new == 0) break; | |
| 1992/0414 | if(new->newcon == s) { | |
| 1992/0306 | qlock(s); | |
| 1991/0424 | s->curlog--; | |
| 1992/0306 | qunlock(s); | |
| 1991/1023 | new->newcon = 0; | |
| 1991/0424 | qunlock(&s->listenq); | |
| 1992/0626 | return new->id; | |
| 1991/0424 | } } | |
| 1992/0414 | qunlock(&s->listenq); | |
| 1992/0307 | print("iplisten: no newcon\n"); | |
| 1991/0424 | } | |
| 1992/0520 | return -1; /* not reached */ | |
| 1991/0424 | } void tcpstclose(Queue *q) { Ipconv *s; | |
| 1992/0626 | Ipconv **etab, **p; | |
| 1991/0424 | Tcpctl *tcb; s = (Ipconv *)(q->ptr); tcb = &s->tcpctl; /* Not interested in data anymore */ | |
| 1992/0223 | qlock(s); | |
| 1991/0424 | s->readq = 0; | |
| 1992/0223 | qunlock(s); | |
| 1991/0424 | switch(tcb->state){ | |
| 1991/12171 | case Listen: | |
| 1992/0416 | /* * reset any incoming calls to this listener */ qlock(s); s->backlog = 0; s->curlog = 0; | |
| 1992/0626 | etab = &tcpbase[Nipconv]; for(p = tcpbase; p < etab && *p; p++){ if((*p)->newcon == s) { (*p)->newcon = 0; tcpflushincoming(*p); | |
| 1992/0416 | } } qunlock(s); qlock(tcb); close_self(s, 0); qunlock(tcb); break; case Closed: | |
| 1991/12171 | case Syn_sent: | |
| 1992/0416 | qlock(tcb); | |
| 1991/0424 | close_self(s, 0); | |
| 1992/0416 | qunlock(tcb); | |
| 1991/0424 | break; | |
| 1992/0313 | ||
| 1991/12171 | case Syn_received: case Established: | |
| 1991/0424 | tcb->sndcnt++; tcb->snd.nxt++; | |
| 1991/12171 | setstate(s, Finwait1); | |
| 1991/0424 | goto output; | |
| 1992/0313 | ||
| 1991/12171 | case Close_wait: | |
| 1991/0424 | tcb->sndcnt++; tcb->snd.nxt++; | |
| 1991/12171 | setstate(s, Last_ack); | |
| 1991/0424 | output: qlock(tcb); | |
| 1992/0322 | if(waserror()) { qunlock(tcb); nexterror(); } | |
| 1991/0424 | tcp_output(s); | |
| 1992/0322 | poperror(); | |
| 1991/0424 | qunlock(tcb); break; } } | |
| 1992/0101 | static short endian = 1; static char* aendian = (char*)&endian; #define LITTLE *aendian | |
| 1991/0424 | ushort | |
| 1992/0101 | ptcl_bsum(uchar *addr, int len) { ulong losum, hisum, mdsum, x; ulong t1, t2; losum = 0; hisum = 0; mdsum = 0; x = 0; if((ulong)addr & 1) { if(len) { hisum += addr[0]; len--; addr++; } x = 1; } while(len >= 16) { t1 = *(ushort*)(addr+0); t2 = *(ushort*)(addr+2); mdsum += t1; t1 = *(ushort*)(addr+4); mdsum += t2; t2 = *(ushort*)(addr+6); mdsum += t1; t1 = *(ushort*)(addr+8); mdsum += t2; t2 = *(ushort*)(addr+10); mdsum += t1; t1 = *(ushort*)(addr+12); mdsum += t2; t2 = *(ushort*)(addr+14); mdsum += t1; mdsum += t2; len -= 16; addr += 16; } while(len >= 2) { mdsum += *(ushort*)addr; len -= 2; addr += 2; } if(x) { if(len) losum += addr[0]; if(LITTLE) losum += mdsum; else hisum += mdsum; } else { if(len) hisum += addr[0]; if(LITTLE) hisum += mdsum; else losum += mdsum; } losum += hisum >> 8; losum += (hisum & 0xff) << 8; while(hisum = losum>>16) losum = hisum + (losum & 0xffff); return losum & 0xffff; } ushort | |
| 1991/0424 | ptcl_csum(Block *bp, int offset, int len) { uchar *addr; | |
| 1992/0101 | ulong losum, hisum; | |
| 1991/0424 | ushort csum; int odd, blen, x; /* Correct to front of data area */ while(bp && offset && offset >= BLEN(bp)) { offset -= BLEN(bp); bp = bp->next; } if(bp == 0) return 0; addr = bp->rptr + offset; blen = BLEN(bp) - offset; | |
| 1992/0101 | if(bp->next == 0) return ~ptcl_bsum(addr, MIN(len, blen)) & 0xffff; losum = 0; hisum = 0; | |
| 1991/0424 | odd = 0; while(len) { | |
| 1992/0101 | x = MIN(len, blen); csum = ptcl_bsum(addr, x); if(odd) hisum += csum; else losum += csum; odd = (odd+x) & 1; len -= x; | |
| 1991/0424 | bp = bp->next; if(bp == 0) break; blen = BLEN(bp); addr = bp->rptr; } losum += hisum>>8; losum += (hisum&0xff)<<8; while((csum = losum>>16) != 0) losum = csum + (losum & 0xffff); return ~losum & 0xffff; } Block * btrim(Block *bp, int offset, int len) { Block *nb, *startb; ulong l; if(blen(bp) < offset+len) { freeb(bp); return 0; } while((l = BLEN(bp)) < offset) { offset -= l; nb = bp->next; bp->next = 0; freeb(bp); bp = nb; } startb = bp; bp->rptr += offset; while((l = BLEN(bp)) < len) { len -= l; bp = bp->next; } bp->wptr -= (BLEN(bp) - len); bp->flags |= S_DELIM; if(bp->next) { freeb(bp->next); bp->next = 0; } return(startb); } Ipconv * | |
| 1992/0626 | portused(Ipifc *ifc, Port port) | |
| 1991/0424 | { | |
| 1992/0626 | Ipconv **p, **etab; Ipconv *cp; | |
| 1991/0424 | ||
| 1992/0406 | if(port == 0) return 0; | |
| 1992/0626 | etab = &ifc->conv[Nipconv]; for(p = ifc->conv; p < etab; p++){ cp = *p; if(cp == 0) break; if(cp->psrc == port) return cp; } | |
| 1991/0424 | return 0; } | |
| 1992/0128 | static Port lastport[2] = { PORTALLOC-1, PRIVPORTALLOC-1 }; | |
| 1991/0424 | Port | |
| 1992/0626 | nextport(Ipifc *ifc, int priv) | |
| 1991/0424 | { | |
| 1992/0128 | Port base; Port max; Port *p; | |
| 1991/0424 | Port i; | |
| 1992/0128 | if(priv){ base = PRIVPORTALLOC; max = PORTALLOC; p = &lastport[1]; } else { base = PORTALLOC; max = PORTMAX; p = &lastport[0]; } for(i = *p + 1; i < max; i++) | |
| 1992/0626 | if(!portused(ifc, i)) | |
| 1992/0128 | return(*p = i); for(i = base ; i <= *p; i++) | |
| 1992/0626 | if(!portused(ifc, i)) | |
| 1992/0128 | return(*p = i); | |
| 1991/12171 | ||
| 1991/0424 | return(0); } /* NEEDS HASHING ! */ | |
| 1992/0626 | Ipconv* | |
| 1992/0711 | ip_conn(Ipifc *ifc, Port dst, Port src, Ipaddr dest) | |
| 1991/0424 | { | |
| 1992/0626 | Ipconv **p, *s, **etab; | |
| 1991/0424 | /* Look for a conversation structure for this port */ | |
| 1992/0626 | etab = &ifc->conv[Nipconv]; for(p = ifc->conv; p < etab; p++) { s = *p; if(s == 0) break; | |
| 1991/12171 | if(s->psrc == dst) if(s->pdst == src) if(s->dst == dest || dest == 0) | |
| 1991/0424 | return s; } return 0; | |
| 1992/0529 | } /* * Fuck me sideways with a bargepole!!! -- philw * * BSD authentication protocol, used on ports 512, 513, & 514. * This makes sure that a user can only write the REAL user id. * * q->ptr is number of nulls seen */ void bsdopen(Queue *q, Stream *s) { | |
| 1992/0711 | USED(s); | |
| 1992/0529 | RD(q)->ptr = q; WR(q)->ptr = q; } void bsdclose(Queue *q) { Block *bp; bp = allocb(0); bp->type = M_HANGUP; PUTNEXT(q->other, bp); } void bsdiput(Queue *q, Block *bp) { PUTNEXT(q, bp); } void bsdoput(Queue *q, Block *bp) { uchar *luser; Block *nbp; /* just pass it on if we've done authentication */ if(q->ptr == 0 || bp->type != M_DATA){ PUTNEXT(q, bp); return; } /* collect into a single block */ | |
| 1992/0602 | qlock(&q->rlock); | |
| 1992/0529 | if(q->first == 0) q->first = pullup(bp, blen(bp)); else{ nbp = q->first; nbp->next = bp; q->first = pullup(nbp, blen(nbp)); } bp = q->first; if(bp == 0){ | |
| 1992/0602 | qunlock(&q->rlock); | |
| 1992/0529 | bsdclose(q); return; } /* look for 2 nulls to indicate stderr port and local user */ luser = memchr(bp->rptr, 0, BLEN(bp)); if(luser == 0){ | |
| 1992/0602 | qunlock(&q->rlock); | |
| 1992/0529 | return; } luser++; if(memchr(luser, 0, bp->wptr - luser) == 0){ | |
| 1992/0602 | qunlock(&q->rlock); | |
| 1992/0529 | return; } /* if luser is a lie, hangup */ if(memcmp(luser, u->p->user, strlen(u->p->user)+1) != 0) bsdclose(q); /* mark queue as authenticated and pass data to remote side */ q->ptr = 0; q->first = 0; bp->flags |= S_DELIM; PUTNEXT(q, bp); | |
| 1992/0602 | qunlock(&q->rlock); | |
| 1991/0424 | } | |