## diffname ip/rudp.c 1998/0630 ## diff -e /dev/null /n/emeliedump/1998/0630/sys/src/brazil/ip/rudp.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" #define DPRINT if(1)print enum { RUDP_PHDRSIZE = 12, RUDP_HDRSIZE = 36, RUDP_RHDRSIZE = 16, RUDP_IPHDR = 8, IP_RUDPPROTO = 254, RUDP_USEAD6 = 36, RUDP_USEAD4 = 12, Rudprxms = 200, Rudptickms = 100, Rudpmaxxmit = 1, }; /* * reliable header */ typedef struct Relhdr Relhdr; struct Relhdr { uchar relseq[4]; /* id of this packet (or 0) */ uchar relsgen[4]; /* generation/time stamp */ uchar relack[4]; /* packet being acked (or 0) */ uchar relagen[4]; /* generation/time stamp */ }; typedef struct Rudphdr Rudphdr; struct Rudphdr { /* ip header */ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar Unused; uchar rudpproto; /* Protocol */ uchar rudpplen[2]; /* Header plus data length */ uchar rudpsrc[4]; /* Ip source */ uchar rudpdst[4]; /* Ip destination */ /* rudp header */ uchar rudpsport[2]; /* Source port */ uchar rudpdport[2]; /* Destination port */ Relhdr rhdr; /* reliable header */ uchar rudplen[2]; /* data length */ uchar rudpcksum[2]; /* Checksum */ }; /* * one state structure per destination */ typedef struct Reliable Reliable; struct Reliable { Reliable *next; uchar addr[IPaddrlen]; /* always V6 when put here */ ushort port; Block *unacked; /* unacked msg list */ Block *unackedtail; /* and its tail */ int timeout; /* time since first unacked msg sent */ int xmits; /* number of times first unacked msg sent */ ulong sndseq; /* next packet to be sent */ ulong sndgen; /* and its generation */ ulong rcvseq; /* last packet received */ ulong rcvgen; /* and its generation */ ulong acksent; /* last ack sent */ ulong ackrcvd; /* last msg for which ack was rcvd */ }; /* MIB II counters */ typedef struct Rudpstats Rudpstats; struct Rudpstats { ulong rudpInDatagrams; ulong rudpNoPorts; ulong rudpInErrors; ulong rudpOutDatagrams; }; typedef struct Rudppriv Rudppriv; struct Rudppriv { /* MIB counters */ Rudpstats ustats; /* non-MIB stats */ ulong csumerr; /* checksum errors */ ulong lenerr; /* short packet */ }; static ulong generation = 0; static Rendez rend; /* * protocol specific part of Conv */ typedef struct Rudpcb Rudpcb; struct Rudpcb { QLock; uchar headers; Reliable *r; }; /* * local functions */ void relsendack( Conv *, Reliable * ); int reliput( Conv *, Block *, uchar *, ushort ); Reliable *relstate( Rudpcb *, uchar *, ushort ); void relackproc( void * ); void relackq( Reliable *, Block * ); void relhangup( Conv *, Reliable * ); void relrexmit( Conv *, Reliable * ); static char* rudpconnect(Conv *c, char **argv, int argc) { char *e; e = Fsstdconnect(c, argv, argc); Fsconnected(c, e); return e; } static int rudpstate(Conv *c, char *state, int n) { USED(c); return snprint(state, n, "%s", "Reliable UDP"); } static char* rudpannounce(Conv *c, char** argv, int argc) { char *e; e = Fsstdannounce(c, argv, argc); if(e != nil) return e; Fsconnected(c, nil); return nil; } static void rudpcreate(Conv *c) { c->rq = qopen(64*1024, 1, 0, 0); c->wq = qopen(64*1024, 0, 0, 0); } static void rudpclose(Conv *c) { Rudpcb *ucb; Reliable *r, *nr; qclose(c->rq); qclose(c->wq); qclose(c->eq); ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); c->lport = 0; c->rport = 0; ucb = (Rudpcb*)c->ptcl; ucb->headers = 0; qlock( ucb ); for( r = ucb->r; r; r = nr ){ nr = r->next; relhangup( c, r ); free( r ); } ucb->r = 0; qunlock( ucb ); unlock(c); } void rudpkick(Conv *c, int) { Rudphdr *uh; ushort rport; uchar laddr[IPaddrlen], raddr[IPaddrlen]; Block *bp; Rudpcb *ucb; Relhdr *rh; Reliable *r; int dlen, ptcllen; Rudppriv *upriv; Fs *f; upriv = c->p->priv; f = c->p->f; netlog(c->p->f, Logrudp, "rudp: kick\n"); bp = qget(c->wq); if(bp == nil) return; ucb = (Rudpcb*)c->ptcl; switch(ucb->headers) { case 6: /* get user specified addresses */ bp = pullupblock(bp, RUDP_USEAD6); if(bp == nil) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if(ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); rport = nhgets(bp->rp); bp->rp += 4; /* Igonore local port */ break; case 4: bp = pullupblock(bp, RUDP_USEAD4); if(bp == nil) return; v4tov6(raddr, bp->rp); bp->rp += IPv4addrlen; v4tov6(laddr, bp->rp); bp->rp += IPv4addrlen; if(ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); rport = nhgets(bp->rp); bp->rp += 4; /* Igonore local port */ break; default: rport = 0; break; } dlen = blocklen(bp); /* Make space to fit rudp & ip header */ bp = padblock(bp, RUDP_IPHDR+RUDP_HDRSIZE); if(bp == nil) return; uh = (Rudphdr *)(bp->rp); rh = &(uh->rhdr); ptcllen = dlen + (RUDP_HDRSIZE-RUDP_PHDRSIZE); uh->Unused = 0; uh->rudpproto = IP_RUDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->rudpplen, ptcllen); switch(ucb->headers){ case 4: case 6: v6tov4(uh->rudpdst, raddr); hnputs(uh->rudpdport, rport); v6tov4(uh->rudpsrc, laddr); break; default: v6tov4(uh->rudpdst, c->raddr); hnputs(uh->rudpdport, c->rport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->rudpsrc, c->laddr); break; } hnputs(uh->rudpsport, c->lport); hnputs(uh->rudplen, ptcllen); uh->rudpcksum[0] = 0; uh->rudpcksum[1] = 0; qlock( ucb ); r = relstate( ucb, raddr, rport ); r->sndseq++; hnputl( rh->relseq, r->sndseq ); hnputl( rh->relsgen, r->sndgen ); hnputl( rh->relack, r->rcvseq ); /* ACK last rcvd packet */ hnputl( rh->relagen, r->rcvgen ); if(r->rcvseq < r->acksent) r->acksent = r->rcvseq; hnputs(uh->rudpcksum, ptclcsum(bp, RUDP_IPHDR, dlen+RUDP_HDRSIZE)); relackq( r, bp ); qunlock( ucb ); upriv->ustats.rudpOutDatagrams++; DPRINT( "sent: %d/%d, %d/%d\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen ); ipoput(f, bp, 0, c->ttl); } void rudpiput(Proto *rudp, uchar *ia, Block *bp) { int len, olen, ottl; Rudphdr *uh; Conv *c, **p; Rudpcb *ucb; uchar raddr[IPaddrlen], laddr[IPaddrlen]; ushort rport, lport; Rudppriv *upriv; Fs *f; upriv = rudp->priv; f = rudp->f; upriv->ustats.rudpInDatagrams++; uh = (Rudphdr*)(bp->rp); /* Put back pseudo header for checksum * (remember old values for icmpnoconv()) */ ottl = uh->Unused; uh->Unused = 0; len = nhgets(uh->rudplen); olen = nhgets(uh->rudpplen); hnputs(uh->rudpplen, len); v4tov6(raddr, uh->rudpsrc); v4tov6(laddr, uh->rudpdst); lport = nhgets(uh->rudpdport); rport = nhgets(uh->rudpsport); if(nhgets(uh->rudpcksum)) { if(ptclcsum(bp, RUDP_IPHDR, len+RUDP_PHDRSIZE)) { upriv->ustats.rudpInErrors++; netlog(f, Logrudp, "rudp: checksum error %I\n", raddr); DPRINT("rudp: checksum error %I\n", raddr); freeblist(bp); return; } } /* Look for a conversation structure for this port */ c = nil; for(p = rudp->conv; *p; p++) { c = *p; if(c->inuse == 0) continue; if(c->lport == lport && (c->rport == 0 || c->rport == rport)) break; } if(*p == nil) { upriv->ustats.rudpNoPorts++; netlog(f, Logrudp, "rudp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); DPRINT( "rudp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); uh->Unused = ottl; hnputs(uh->rudpplen, olen); icmpnoconv(f, bp); freeblist(bp); return; } ucb = (Rudpcb*)c->ptcl; qlock( ucb ); if( reliput( c, bp, raddr, rport ) < 0 ){ qunlock( ucb ); freeb( bp ); return; } /* * Trim the packet down to data size */ len -= (RUDP_HDRSIZE-RUDP_PHDRSIZE); bp = trimblock(bp, RUDP_IPHDR+RUDP_HDRSIZE, len); if(bp == nil){ netlog(f, Logrudp, "rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); DPRINT( "rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); upriv->lenerr++; return; } netlog(f, Logrudpmsg, "rudp: %I.%d -> %I.%d l %d\n", raddr, rport, laddr, lport, len); switch(ucb->headers){ case 6: /* pass the src address */ bp = padblock(bp, RUDP_USEAD6); ipmove(bp->rp, raddr); if(ipforme(f, laddr) == Runi) ipmove(bp->rp+IPaddrlen, laddr); else ipmove(bp->rp+IPaddrlen, ia); hnputs(bp->rp+2*IPaddrlen, rport); hnputs(bp->rp+2*IPaddrlen+2, lport); break; case 4: /* pass the src address */ bp = padblock(bp, RUDP_USEAD4); v6tov4(bp->rp, raddr); if(ipforme(f, laddr) == Runi) v6tov4(bp->rp+IPv4addrlen, laddr); else v6tov4(bp->rp+IPv4addrlen, ia); hnputs(bp->rp + 2*IPv4addrlen, rport); hnputs(bp->rp + 2*IPv4addrlen + 2, lport); break; default: /* connection oriented rudp */ if(c->raddr == 0){ /* save the src address in the conversation */ ipmove(c->raddr, raddr); c->rport = rport; /* reply with the same ip address (if not broadcast) */ if(ipforme(f, laddr) == Runi) ipmove(c->laddr, laddr); else v4tov6(c->laddr, ia); } break; } if(bp->next) bp = concatblock(bp); if(qfull(c->rq)){ netlog(f, Logrudp, "rudp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); freeblist(bp); } else qpass(c->rq, bp); qunlock( ucb ); } char* rudpctl(Conv *c, char **f, int n) { Rudpcb *ucb; ucb = (Rudpcb*)c->ptcl; if(n == 1){ if(strcmp(f[0], "headers4") == 0){ ucb->headers = 4; return nil; } else if(strcmp(f[0], "headers") == 0){ ucb->headers = 6; return nil; } } return "unknown control request"; } void rudpadvise(Proto *rudp, Block *bp, char *msg) { Rudphdr *h; uchar source[IPaddrlen], dest[IPaddrlen]; ushort psource, pdest; Conv *s, **p; h = (Rudphdr*)(bp->rp); v4tov6(dest, h->rudpdst); v4tov6(source, h->rudpsrc); psource = nhgets(h->rudpsport); pdest = nhgets(h->rudpdport); /* Look for a connection */ for(p = rudp->conv; *p; p++) { s = *p; if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ qhangup(s->rq, msg); qhangup(s->wq, msg); break; } } freeblist(bp); } int rudpstats(Proto *rudp, char *buf, int len) { Rudppriv *upriv; upriv = rudp->priv; return snprint(buf, len, "%d %d %d %d\n", upriv->ustats.rudpInDatagrams, upriv->ustats.rudpNoPorts, upriv->ustats.rudpInErrors, upriv->ustats.rudpOutDatagrams); } void rudpinit(Fs *fs) { Proto *rudp; rudp = smalloc(sizeof(Proto)); rudp->priv = smalloc(sizeof(Rudppriv)); rudp->name = "rudp"; rudp->kick = rudpkick; rudp->connect = rudpconnect; rudp->announce = rudpannounce; rudp->ctl = rudpctl; rudp->state = rudpstate; rudp->create = rudpcreate; rudp->close = rudpclose; rudp->rcv = rudpiput; rudp->advise = rudpadvise; rudp->stats = rudpstats; rudp->ipproto = IP_RUDPPROTO; rudp->nc = 16; rudp->ptclsize = sizeof(Rudpcb); Fsproto(fs, rudp); kproc( "relackproc", relackproc, rudp ); } /*********************************************/ /* Here starts the reliable helper functions */ /*********************************************/ /* * Enqueue a copy of an unacked block for possible retransmissions */ void relackq(Reliable *r, Block *bp) { Block *np; np = copyblock(bp, blocklen(bp)); if(r->unacked) r->unackedtail->list = np; else { /* restart timer */ r->timeout = 0; r->xmits = 1; r->unacked = np; } r->unackedtail = np; np->list = nil; } /* * retransmit unacked blocks */ void relackproc(void *a) { Rudpcb *ucb; Proto *rudp; Reliable *r; Conv **s, *c; rudp = (Proto *)a; loop: tsleep(&rend, return0, 0, Rudptickms); for(s = rudp->conv; *s; s++) { c = *s; ucb = (Rudpcb*)c->ptcl; qlock( ucb ); for(r = ucb->r; r; r = r->next){ if(r->unacked != nil){ r->timeout += Rudptickms; if(r->timeout > Rudprxms*r->xmits) relrexmit(c, r); } if(r->acksent < r->rcvseq) relsendack(c, r); } qunlock( ucb ); } goto loop; } /* * get the state record for a conversation */ Reliable* relstate(Rudpcb *ucb, uchar *addr, ushort port) { Reliable *r, **l; l = &ucb->r; for(r = *l; r; r = *l){ if( memcmp( addr, r->addr, IPaddrlen) == 0 && port == r->port) break; l = &r->next; } /* no state for this addr/port, create some */ if(r == nil){ DPRINT( "new state %d\n", generation ); if(generation == 0) generation = TK2SEC(MACHP(0)->ticks); r = smalloc( sizeof( Reliable ) ); *l = r; memmove( r->addr, addr, IPaddrlen); r->port = port; r->unacked = 0; r->sndgen = generation++; r->sndseq = 0; r->ackrcvd = 0; r->rcvgen = 0; r->rcvseq = 0; r->acksent = 0; r->xmits = 0; r->timeout = 0; } return r; } /* * process a rcvd reliable packet. return -1 if not to be passed to user process, * 0 therwise. */ int reliput(Conv *c, Block *bp, uchar *addr, ushort port) { Block *nbp; Rudpcb *ucb; Rudphdr *uh; Reliable *r; Relhdr *rh; ulong seq, ack, sgen, agen, ackreal; /* get fields */ uh = (Rudphdr *)(bp->rp); rh = &(uh->rhdr); seq = nhgetl(rh->relseq); sgen = nhgetl(rh->relsgen); ack = nhgetl(rh->relack); agen = nhgetl(rh->relagen); ucb = (Rudpcb*)c->ptcl; r = relstate(ucb, addr, port); DPRINT("rcvd %d/%d, %d/%d, r->sndgen = %d, r->ackrcvd = %d\n", seq, sgen, ack, agen, r->sndgen, r->ackrcvd); /* dequeue acked packets */ if(ack && agen == r->sndgen){ DPRINT( "Here\n" ); ackreal = 0; while(r->unacked != nil && ack > r->ackrcvd){ nbp = r->unacked; r->unacked = nbp->list; DPRINT("%d/%d acked\n", ack, agen); freeb(nbp); r->ackrcvd++; ackreal = 1; } /* * retransmit next packet if the acked packet * was transmitted more than once */ if(ackreal && r->unacked != nil){ r->timeout = 0; if(r->xmits > 1){ r->xmits = 1; relrexmit(c, r); } } } /* make sure we're not talking to a new remote side */ if(r->rcvgen != sgen){ if(seq != 1) return -1; /* new connection */ if(r->rcvgen != 0){ DPRINT("new con r->rcvgen = %d, sgen = %d\n", r->rcvgen, sgen); relhangup(c, r); } r->rcvgen = sgen; } /* no message */ if(seq == 0) return -1; /* refuse out of order delivery */ if(seq != r->rcvseq + 1){ DPRINT("out of sequence %d not %d\n", seq, r->rcvseq + 1); return -1; } r->rcvseq = seq; return 0; } void relsendack(Conv *c, Reliable *r) { Rudphdr *uh; Block *bp; Relhdr *rh; int ptcllen; Fs *f; bp = allocb(RUDP_IPHDR + RUDP_HDRSIZE); if(bp == nil) return; bp->wp += RUDP_IPHDR + RUDP_HDRSIZE; f = c->p->f; uh = (Rudphdr *)(bp->rp); rh = &(uh->rhdr); ptcllen = (RUDP_HDRSIZE-RUDP_PHDRSIZE); uh->Unused = 0; uh->rudpproto = IP_RUDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->rudpplen, ptcllen); v6tov4( uh->rudpdst, r->addr ); hnputs(uh->rudpdport, r->port); hnputs(uh->rudpsport, c->lport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->rudpsrc, c->laddr); hnputs(uh->rudplen, ptcllen); hnputl(rh->relsgen, r->sndgen); hnputl(rh->relseq, 0); hnputl(rh->relagen, r->rcvgen); hnputl(rh->relack, r->rcvseq); if(r->acksent < r->rcvseq) r->acksent = r->rcvseq; uh->rudpcksum[0] = 0; uh->rudpcksum[1] = 0; hnputs(uh->rudpcksum, ptclcsum(bp, RUDP_IPHDR, RUDP_HDRSIZE)); DPRINT( "sendack: %d/%d, %d/%d\n", 0, r->sndgen, r->rcvseq, r->rcvgen ); ipoput(f, bp, 0, c->ttl); } /* * called with ucb locked (and c locked if user initiated close) */ void relhangup( Conv *, Reliable *r ) { Block *bp; /* * dump any unacked outgoing messages */ for(bp = r->unacked; bp != nil; bp = r->unacked){ r->unacked = bp->list; bp->list = nil; freeb(bp); } r->rcvgen = 0; r->rcvseq = 0; r->acksent = 0; r->sndgen = generation++; r->sndseq = 0; r->ackrcvd = 0; r->xmits = 0; r->timeout = 0; } /* * called with ucb locked */ void relrexmit(Conv *c, Reliable *r) { Block *np; Fs *f; f = c->p->f; r->timeout = 0; if(r->xmits++ > Rudpmaxxmit){ relhangup(c, r); return; } np = copyblock(r->unacked, blocklen(r->unacked)); //DPRINT("rxmit r->ackrvcd+1 = %d\n", r->ackrcvd+1); ipoput(f, np, 0, c->ttl); } . ## diffname ip/rudp.c 1998/0726 ## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0726/sys/src/brazil/ip/rudp.c 859c DPRINT("rxmit r->ackrvcd+1 = %d\n", r->ackrcvd+1); . 857a upriv->rxmits++; . 850a upriv = c->p->priv; . 848a Rudppriv *upriv; . 755a upriv->orders++; . 753a if( DEBUG && ++drop == drop_rate ){ DPRINT( "drop pkt on purpose\n" ); drop = 0; return -1; } . 716c DPRINT("%d/%d acked, r->sndgen = %d\n", ack, agen, r->sndgen); . 711d 706,707c DPRINT("rcvd %d/%d, %d/%d, r->sndgen = %d\n", seq, sgen, ack, agen, r->sndgen); . 703c r = relstate(ucb, addr, port, "input" ); . 701c upriv = c->p->priv; . 684a Rudppriv *upriv; . 656a DPRINT( "from %s new state %d for %I!%d\n", from, generation, addr, port ); . 654d 643a . 639c relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from ) . 630c qunlock(ucb); . 620,621c for(r = ucb->r; r; r = r->next) { . 618c qlock(ucb); . 613c tsleep(&upriv->vous, return0, 0, Rudptickms); . 611a upriv = rudp->priv; . 609a Rudppriv *upriv; . 572c kproc("relackproc", relackproc, rudp); . 544c upriv->ustats.rudpOutDatagrams, upriv->rxmits, upriv->orders); . 540c return snprint(buf, len, "%d %d %d %d %d %d\n", . 374a upriv->csumerr++; . 331,332c DPRINT( "sent: %d/%d, %d/%d, r->sndgen = %d\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen, r->sndgen ); . 311c r = relstate( ucb, raddr, rport, "kick" ); . 282a . 267c ipmove( raddr, c->raddr ); ipmove( laddr, c->laddr ); rport = c->rport; . 160c return snprint(state, n, "%s", "Reliable UDP V0.1"); . 138c Reliable *relstate( Rudpcb *, uchar *, ushort, char *from ); . 121a /* Used only for debugging */ static ushort drop = 0; static ushort drop_rate = 10; . 114,115c ulong csumerr; /* checksum errors */ ulong lenerr; /* short packet */ ulong rxmits; /* # of retransmissions */ ulong orders; /* # of out of order pkts */ . 109d 107a Rendez vous; . 25c Rudpmaxxmit = 10, . 11c #define DEBUG 0 #define DPRINT if(DEBUG)print . ## diffname ip/rudp.c 1998/0728 ## diff -e /n/emeliedump/1998/0726/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0728/sys/src/brazil/ip/rudp.c 846c relhangup(Conv *, Reliable *r) . 838c DPRINT("sendack: %d/%d, %d/%d\n", 0, r->sndgen, r->rcvseq, r->rcvgen); . 834,836c uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE)); . 824,825d 821,822c v6tov4(uh->udpsrc, c->laddr); hnputs(uh->udplen, ptcllen); . 814,818c v6tov4(uh->udpdst, r->addr); hnputs(uh->udpdport, r->port); hnputs(uh->udpsport, c->lport); . 812c hnputs(uh->udpplen, ptcllen); . 809c uh->udpproto = IP_UDPPROTO; . 807c ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE); . 804,805c uh = (Udphdr *)(bp->rp); rh = (Rudphdr*)uh; . 802c bp->wp += UDP_IPHDR + UDP_RHDRSIZE; . 799c bp = allocb(UDP_IPHDR + UDP_RHDRSIZE); . 795c Rudphdr *rh; . 793c Udphdr *uh; . 773,774c if(DEBUG && ++drop == drop_rate){ DPRINT("drop pkt on purpose\n"); . 722c r = relstate(ucb, addr, port, "input"); . 712,713c uh = (Udphdr*)(bp->rp); rh = (Rudphdr*)uh; . 706c Rudphdr *rh; . 704c Udphdr *uh; . 677c memmove(r->addr, addr, IPaddrlen); . 673,675c DPRINT("from %s new state %d for %I!%d\n", from, generation, addr, port); r = smalloc(sizeof(Reliable)); . 663c if(memcmp(addr, r->addr, IPaddrlen) == 0 && . 659,660d 655c relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from) . 580c rudp->ipproto = IP_UDPPROTO; . 526,529c v4tov6(dest, h->udpdst); v4tov6(source, h->udpsrc); psource = nhgets(h->udpsport); pdest = nhgets(h->udpdport); . 524c h = (Udphdr*)(bp->rp); . 519c Udphdr *h; . 495c qunlock(ucb); . 460c bp = padblock(bp, UDP_USEAD4); . 449c bp = padblock(bp, UDP_USEAD6); . 444,445d 435c DPRINT("rudp: len err %I.%d -> %I.%d\n", . 430,431c len -= (UDP_RHDRSIZE-UDP_PHDRSIZE); bp = trimblock(bp, UDP_IPHDR+UDP_RHDRSIZE, len); . 419,422c qlock(ucb); if(reliput(c, bp, raddr, rport) < 0){ qunlock(ucb); freeb(bp); . 411c hnputs(uh->udpplen, olen); . 408c DPRINT("rudp: no conv %I!%d -> %I!%d\n", raddr, rport, . 400,401c if(c->lport == lport){ ucb = (Rudpcb*)c->ptcl; /* with headers turned on, descriminate only on local port */ if(ucb->headers) break; /* otherwise discriminate on lport, rport, and raddr */ if(c->rport == 0 || c->rport == rport) if(ipisbm(c->raddr) || ipcmp(c->raddr, IPnoaddr) == 0 || ipcmp(c->raddr, raddr) == 0) break; } . 381,384c if(nhgets(uh->udpcksum)) { if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { . 376,379c v4tov6(raddr, uh->udpsrc); v4tov6(laddr, uh->udpdst); lport = nhgets(uh->udpdport); rport = nhgets(uh->udpsport); . 372,374c len = nhgets(uh->udplen); olen = nhgets(uh->udpplen); hnputs(uh->udpplen, len); . 365c uh = (Udphdr*)(bp->rp); . 352c Udphdr *uh; . 341,344d 339a DPRINT("sent: %d/%d, %d/%d, r->sndgen = %d\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen, r->sndgen); . 335,336c relackq(r, bp); qunlock(ucb); . 333c hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE)); . 327,328c hnputl(rh->relack, r->rcvseq); /* ACK last rcvd packet */ hnputl(rh->relagen, r->rcvgen); . 324,325c hnputl(rh->relseq, r->sndseq); hnputl(rh->relsgen, r->sndgen); . 320,322c qlock(ucb); r = relstate(ucb, raddr, rport, "kick"); . 315,318c hnputs(uh->udpsport, c->lport); hnputs(uh->udplen, ptcllen); uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; . 312c v6tov4(uh->udpsrc, c->laddr); . 308,309c v6tov4(uh->udpdst, c->raddr); hnputs(uh->udpdport, c->rport); . 303,305c v6tov4(uh->udpdst, raddr); hnputs(uh->udpdport, rport); v6tov4(uh->udpsrc, laddr); . 299c hnputs(uh->udpplen, ptcllen); . 296c uh->udpproto = IP_UDPPROTO; . 293,294c ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE); . 291c rh = (Rudphdr*)uh; . 289c uh = (Udphdr *)(bp->rp); . 285c bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE); . 275,276c ipmove(raddr, c->raddr); ipmove(laddr, c->laddr); . 261c bp = pullupblock(bp, UDP_USEAD4); . 246c bp = pullupblock(bp, UDP_USEAD6); . 228c Rudphdr *rh; . 223c Udphdr *uh; . 215c qunlock(ucb); . 210,211c relhangup(c, r); free(r); . 207,208c qlock(ucb); for(r = ucb->r; r; r = nr){ . 144,150c void relsendack(Conv *, Reliable *); int reliput(Conv *, Block *, uchar *, ushort); Reliable *relstate(Rudpcb *, uchar *, ushort, char *from); void relackproc(void *); void relackq(Reliable *, Block *); void relhangup(Conv *, Reliable *); void relrexmit(Conv *, Reliable *); . 77d 58,62c uchar relseq[4]; /* id of this packet (or 0) */ uchar relsgen[4]; /* generation/time stamp */ uchar relack[4]; /* packet being acked (or 0) */ uchar relagen[4]; /* generation/time stamp */ . 56a /* pseudo header starts here */ uchar Unused; uchar udpproto; /* Protocol */ uchar udpplen[2]; /* Header plus data length */ uchar udpsrc[4]; /* Ip source */ uchar udpdst[4]; /* Ip destination */ /* udp header */ uchar udpsport[2]; /* Source port */ uchar udpdport[2]; /* Destination port */ uchar udplen[2]; /* data length (includes rudp header) */ uchar udpcksum[2]; /* Checksum */ . 51,55d 36,39c /* ip header */ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ /* pseudo header starts here */ uchar Unused; uchar udpproto; /* Protocol */ uchar udpplen[2]; /* Header plus data length */ uchar udpsrc[4]; /* Ip source */ uchar udpdst[4]; /* Ip destination */ /* udp header */ uchar udpsport[2]; /* Source port */ uchar udpdport[2]; /* Destination port */ uchar udplen[2]; /* data length */ uchar udpcksum[2]; /* Checksum */ . 30,34c typedef struct Udphdr Udphdr; struct Udphdr . 16,22c UDP_HDRSIZE = 20, /* pseudo header + udp header */ UDP_PHDRSIZE = 12, /* pseudo header */ UDP_RHDRSIZE = 36, /* pseudo header + udp header + rudp header */ UDP_IPHDR = 8, /* ip header */ IP_UDPPROTO = 254, UDP_USEAD6 = 36, UDP_USEAD4 = 12, . 1c /* * This protocol is compatible with UDP's packet format. * It could be done over UDP if need be. */ . ## diffname ip/rudp.c 1998/0731 ## diff -e /n/emeliedump/1998/0728/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0731/sys/src/brazil/ip/rudp.c 730,731d 694c generation = rand(); . 495c if(ipcmp(c->raddr, IPnoaddr) == 0){ . ## diffname ip/rudp.c 1998/0801 ## diff -e /n/emeliedump/1998/0731/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0801/sys/src/brazil/ip/rudp.c 882a wakeup(&r->vous); . 802c DPRINT("out of sequence %d not %d\n", seq, NEXTSEQ(r->rcvseq)); . 800c if(seq != NEXTSEQ(r->rcvseq)){ . 789,790c /* no message or input queue full */ if(seq == 0 || qfull(c->rq)) . 780d 760a /* flow control */ if(UNACKED(r) < Maxunacked/8 && r->blocked) wakeup(&r->vous); . 757c r->ackrcvd = NEXTSEQ(r->ackrcvd); . 751c while(r->unacked != nil && INSEQ(ack, r->ackrcvd, r->sndseq)){ . 739d 667c if(r->acksent != r->rcvseq) . 362a /* flow control of sorts */ qlock(&r->lock); if(UNACKED(r) > Maxunacked){ r->blocked = 1; sleep(&r->vous, flow, r); r->blocked = 0; } qunlock(&r->lock); . 349c if(r->rcvseq != r->acksent) . 342c r->sndseq = NEXTSEQ(r->sndseq); . 240a int flow(Reliable *r) { return UNACKED(r) <= Maxunacked; } . 188,189c Rudpcb *ucb; Reliable *r; int m; m = snprint(state, n, "%s", c->inuse?"Open":"Closed"); ucb = (Rudpcb*)c->ptcl; qlock(ucb); for(r = ucb->r; r; r = r->next) m += snprint(state+m, n-m, " %I/%d", r->addr, UNACKED(r)); qunlock(ucb); return m; . 112a /* flow control */ QLock lock; Rendez vous; int blocked; . 96c uchar addr[IPaddrlen]; /* always V6 when put here */ . 30c Maxunacked = 100, . 16a #define SEQDIFF(a,b) ( (a)>=(b)?\ (a)-(b):\ 0xffffffffUL-((b)-(a)) ) #define INSEQ(a,start,end) ( (start)<=(end)?\ ((a)>(start)&&(a)<=(end)):\ ((a)>(start)||(a)<=(end)) ) #define UNACKED(r) SEQDIFF(r->sndseq, r->ackrcvd) #define NEXTSEQ(a) ( (a)+1 == 0 ? 1 : (a)+1 ) . ## diffname ip/rudp.c 1998/0825 ## diff -e /n/emeliedump/1998/0801/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0825/sys/src/brazil/ip/rudp.c 946c DPRINT("rxmit r->ackrvcd+1 = %lud\n", r->ackrcvd+1); . 894c DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen); . 842c DPRINT("out of sequence %lud not %lud\n", seq, NEXTSEQ(r->rcvseq)); . 823c DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen); . 791c DPRINT("%lud/%lud acked, r->sndgen = %lud\n", . 782c DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n", . 733c DPRINT("from %s new state %lud for %I!%ud\n", . 614c return snprint(buf, len, "%lud %lud %lud %lud %lud %lud\n", . 388,389c DPRINT("sent: %lud/%lud, %lud/%lud\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen); . 210c m += snprint(state+m, n-m, " %I/%ld", r->addr, UNACKED(r)); . ## diffname ip/rudp.c 1998/0924 ## diff -e /n/emeliedump/1998/0825/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/0924/sys/src/brazil/ip/rudp.c 647,649d 219a rudpstartackproc(c->p); . 191a rudpstartackproc(c->p); . 186a static void rudpstartackproc(Proto *rudp) { Rudppriv *rpriv; char kpname[NAMELEN]; rpriv = rudp->priv; if(rpriv->ackprocstarted == 0){ qlock(&rpriv->apl); if(rpriv->ackprocstarted == 0){ sprint(kpname, "#I%drudpack", rudp->f->dev); kproc(kpname, relackproc, rudp); rpriv->ackprocstarted = 1; } qunlock(&rpriv->apl); } } . 154a /* keeping track of the ack kproc */ int ackprocstarted; QLock apl; . ## diffname ip/rudp.c 1998/1117 ## diff -e /n/emeliedump/1998/0924/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/1117/sys/src/brazil/ip/rudp.c 860a relsendack(c, r); /* tell him we got it already */ . 37c Rudptickms = 50, . ## diffname ip/rudp.c 1998/1118 ## diff -e /n/emeliedump/1998/1117/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/1118/sys/src/brazil/ip/rudp.c 968c doipoput(c, f, np, 0, c->ttl); . 926a n = snprint(hup, sizeof(hup), "hangup %I!%d", r->addr, r->port); qproduce(c->eq, hup, n); . 925a char hup[ERRLEN]; . 924a int n; . 923c relhangup(Conv *c, Reliable *r) . 916c doipoput(c, f, bp, 0, c->ttl); . 853,858d 836,848d 804a /* make sure we're not talking to a new remote side */ if(r->rcvgen != sgen){ if(seq != 1) return -1; /* new connection */ if(r->rcvgen != 0){ DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen); relhangup(c, r); } r->rcvgen = sgen; } . 595a } else if(strcmp(f[0], "randdrop") == 0){ ucb->randdrop = 1; return nil; . 414c doipoput(c, f, bp, 0, c->ttl); . 286a /* * randomly don't send packets */ static void doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl) { Rudpcb *ucb; ucb = (Rudpcb*)c->ptcl; if(ucb->randdrop && nrand(10) == 1) freeblist(bp); else ipoput(f, bp, x, ttl); } . 275a if(r->acksent != r->rcvseq) relsendack(c, r); . 273a ucb->randdrop = 0; . 272d 263a /* force out any delayed acks */ ucb = (Rudpcb*)c->ptcl; qlock(ucb); for(r = ucb->r; r; r = r->next){ if(r->acksent != r->rcvseq) relsendack(c, r); } qunlock(ucb); . 175a uchar randdrop; . 164,167d ## diffname ip/rudp.c 1998/1124 ## diff -e /n/emeliedump/1998/1118/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/1124/sys/src/brazil/ip/rudp.c 830a /* if acking an incorrect generation, ignore */ if(ack && agen != r->sndgen) return -1; . ## diffname ip/rudp.c 1998/1127 ## diff -e /n/emeliedump/1998/1124/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/1127/sys/src/brazil/ip/rudp.c 837c if(seq != 0 && seq != 1) . 777c while(generation == 0) . ## diffname ip/rudp.c 1998/1230 ## diff -e /n/emeliedump/1998/1127/sys/src/brazil/ip/rudp.c /n/emeliedump/1998/1230/sys/src/brazil/ip/rudp.c 624c return rudpunknown; . 612,622c if(n < 1) return rudpunknown; if(strcmp(f[0], "headers4") == 0){ ucb->headers = 4; return nil; } else if(strcmp(f[0], "headers") == 0){ ucb->headers = 6; return nil; } else if(strcmp(f[0], "randdrop") == 0){ x = 10; /* default is 10% */ if(n > 1) x = atoi(f[1]); if(x > 100 || x < 0) return "illegal rudp drop rate"; ucb->randdrop = x; return nil; . 609a int x; . 605a static char *rudpunknown = "unknown rudp ctl request"; . 304c if(ucb->randdrop && nrand(100) < ucb->randdrop) . ## diffname ip/rudp.c 1999/0302 ## diff -e /n/emeliedump/1998/1230/sys/src/brazil/ip/rudp.c /n/emeliedump/1999/0302/sys/src/brazil/ip/rudp.c 529a qunlock(rudp); . 528d 514a qunlock(rudp); . 492a qlock(rudp); . 292c qunlock(c); . ## diffname ip/rudp.c 1999/0320 ## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/rudp.c /n/emeliedump/1999/0320/sys/src/brazil/ip/rudp.c 312a Reliable *r = v; . 311c flow(void *v) . ## diffname ip/rudp.c 1999/0817 ## diff -e /n/emeliedump/1999/0320/sys/src/brazil/ip/rudp.c /n/emeliedump/1999/0817/sys/src/brazil/ip/rudp.c 1012c doipoput(c, f, np, 0, c->ttl, c->tos); . 955c doipoput(c, f, bp, 0, c->ttl, c->tos); . 439c doipoput(c, f, bp, 0, c->ttl, c->tos); . 307c ipoput(f, bp, x, ttl, tos); . 299c doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl, int tos) . ## diffname ip/rudp.c 2000/0317 ## diff -e /n/emeliedump/1999/0817/sys/src/brazil/ip/rudp.c /n/emeliedump/2000/0317/sys/src/9/ip/rudp.c 982a if(generation == Hangupgen) generation++; . 957a . 942c if(hangup) hnputl(rh->relsgen, Hangupgen); else hnputl(rh->relsgen, r->sndgen); . 911c relsendack(Conv *c, Reliable *r, int hangup) . 907c rv = 0; out: relput(r); qunlock(ucb); return rv; . 903c goto out; . 900c relsendack(c, r, 0); /* tell him we got it already */ . 896c goto out; . 853c goto out; . 849a /* Look for a hangup */ if(sgen == Hangupgen) { if(agen == r->sndgen) relforget(c, addr, port, 0); goto out; } . 848c goto out; . 841d 839a qlock(ucb); . 828a int rv = -1; . 814a void relforget(Conv *c, uchar *ip, int port, int originator) { Rudpcb *ucb; Reliable *r, **l; ucb = (Rudpcb*)c->ptcl; l = &ucb->r; for(r = *l; r; r = *l){ if(ipcmp(ip, r->addr) == 0 && port == r->port){ *l = r->next; if(originator) relsendack(c, r, 1); relhangup(c, r); relput(r); /* remove from the list */ break; } l = &r->next; } } . 813a void relput(Reliable *r) { if(decref(r) == 0) free(r); } . 810c incref(r); . 808a r->ref = 0; incref(r); /* one reference for being in the list */ . 800a if(generation == Hangupgen) generation++; . 767c relsendack(c, r, 0); . 629a } else if(strcmp(f[0], "hangup") == 0){ if(n < 3) return "bad syntax"; parseip(ip, f[1]); x = atoi(f[2]); qlock(ucb); relforget(c, ip, x, 1); qunlock(ucb); return nil; . 617a uchar ip[IPaddrlen]; . 448c relput(r); qunlock(ucb); . 442d 432d 283c relsendack(c, r, 0); . 266c relsendack(c, r, 0); . 181a void relput(Reliable *); void relforget(Conv *, uchar *, int, int); . 179c void relsendack(Conv *, Reliable *, int); . 124d 102a Ref; . 41a #define Hangupgen 0xffffffff /* used only in hangup messages */ . 39a . ## diffname ip/rudp.c 2000/0328 ## diff -e /n/emeliedump/2000/0317/sys/src/9/ip/rudp.c /n/emeliedump/2000/0328/sys/src/9/ip/rudp.c 453d 451a qunlock(&r->lock); . 446a qlock(&r->lock); . 437a qunlock(ucb); . 128a QLock lock; . ## diffname ip/rudp.c 2000/0403 ## diff -e /n/emeliedump/2000/0328/sys/src/9/ip/rudp.c /n/emeliedump/2000/0403/sys/src/9/ip/rudp.c 968d 891d 867a * * called with ucb locked. . 842a /* * forget a Reliable state */ . 830a *l = r; . 815d 813a . 455a . 293c relput(r); . ## diffname ip/rudp.c 2000/0605 ## diff -e /n/emeliedump/2000/0403/sys/src/9/ip/rudp.c /n/emeliedump/2000/0605/sys/src/9/ip/rudp.c 834a . 812a . 610c if(qfull(c->rq)) { . 557c if(bp == nil) { . 457a poperror(); . 456a qunlock(&r->lock); . 455d 447a if(waserror()) { relput(r); qunlock(&r->lock); nexterror(); } . 298d 190,192c void relackq(Reliable *, Block*); void relhangup(Conv *, Reliable*); void relrexmit(Conv *, Reliable*); void relput(Reliable*); . 184,188c void relsendack(Conv*, Reliable*, int); int reliput(Conv*, Block*, uchar*, ushort); Reliable *relstate(Rudpcb*, uchar*, ushort, char*); void relput(Reliable*); void relforget(Conv *, uchar*, int, int); . ## diffname ip/rudp.c 2000/1220 ## diff -e /n/emeliedump/2000/0605/sys/src/9/ip/rudp.c /n/emeliedump/2000/1220/sys/src/9/ip/rudp.c 299d ## diffname ip/rudp.c 2001/0301 ## diff -e /n/emeliedump/2000/1220/sys/src/9/ip/rudp.c /n/emeliedump/2001/0301/sys/src/9/ip/rudp.c 546d 538,539d 536c qunlock(rudp); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, . 512,534c c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); if(c == nil){ /* no converstation found */ . 471c Conv *c; . 268a upriv = c->p->priv; iphtrem(&upriv->ht, c); . 267a Rudppriv *upriv; . 251a iphtadd(&upriv->ht, c); . 246a upriv = c->p->priv; . 245a Rudppriv *upriv; . 220a iphtadd(&upriv->ht, c); . 217a upriv = c->p->priv; . 216a Rudppriv *upriv; . 149a Ipht ht; . ## diffname ip/rudp.c 2001/0306 ## diff -e /n/emeliedump/2001/0301/sys/src/9/ip/rudp.c /n/emeliedump/2001/0306/sys/src/9/ip/rudp.c 336c rudpkick(Conv *c) . ## diffname ip/rudp.c 2001/0623 ## diff -e /n/emeliedump/2001/0306/sys/src/9/ip/rudp.c /n/emeliedump/2001/0623/sys/src/9/ip/rudp.c 598c v4tov6(c->laddr, ifc->lifc->local); . 583c v6tov4(bp->rp+IPv4addrlen, ifc->lifc->local); . 572c ipmove(bp->rp+IPaddrlen, ifc->lifc->local); . 478c rudpiput(Proto *rudp, Ipifc *ifc, Block *bp) . ## diffname ip/rudp.c 2001/0918 ## diff -e /n/emeliedump/2001/0623/sys/src/9/ip/rudp.c /n/emeliedump/2001/0918/sys/src/9/ip/rudp.c 1035c char hup[ERRMAX]; . 200c char kpname[KNAMELEN]; . ## diffname ip/rudp.c 2002/0507 ## diff -e /n/emeliedump/2001/0918/sys/src/9/ip/rudp.c /n/emeliedump/2002/0507/sys/src/9/ip/rudp.c 989a uh->vihl = IP_VER4; . 404a uh->vihl = IP_VER4; . 324c ipoput4(f, bp, x, ttl, tos); . ## diffname ip/rudp.c 2002/0711 ## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/rudp.c /n/emeliedump/2002/0711/sys/src/9/ip/rudp.c 266c c->rq = qopen(64*1024, Qmsg, 0, 0); . ## diffname ip/rudp.c 2002/0712 ## diff -e /n/emeliedump/2002/0711/sys/src/9/ip/rudp.c /n/emeliedump/2002/0712/sys/src/9/ip/rudp.c 711d 337a Conv *c = x; . 336c rudpkick(void *x) . 267c c->wq = qopen(64*1024, Qkick, rudpkick, c); . 194a void rudpkick(void *x); . ## diffname ip/rudp.c 2003/0308 ## diff -e /n/emeliedump/2002/0712/sys/src/9/ip/rudp.c /n/emeliedump/2003/0308/sys/src/9/ip/rudp.c 325c ipoput4(f, bp, x, ttl, tos, nil); . ## diffname ip/rudp.c 2003/0407 ## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/rudp.c /n/emeliedump/2003/0407/sys/src/9/ip/rudp.c 769c tsleep(&up->sleep, return0, 0, Rudptickms); . 149d ## diffname ip/rudp.c 2003/0409 ## diff -e /n/emeliedump/2003/0407/sys/src/9/ip/rudp.c /n/emeliedump/2003/0409/sys/src/9/ip/rudp.c 765d 762d ## diffname ip/rudp.c 2003/0419 ## diff -e /n/emeliedump/2003/0409/sys/src/9/ip/rudp.c /n/emeliedump/2003/0419/sys/src/9/ip/rudp.c 631,632c if(strcmp(f[0], "headers++4") == 0){ ucb->headers = 7; . 578,588d 570,576c p = bp->rp; ipmove(p, raddr); p += IPaddrlen; ipmove(p, ipforme(f, laddr)==Runi ? laddr : ifc->lifc->local); p += IPaddrlen; hnputs(p, rport); p += 2; hnputs(p, lport); . 566a case 7: /* pass the src address */ bp = padblock(bp, UDP_USEAD7); p = bp->rp; ipmove(p, raddr); p += IPaddrlen; ipmove(p, laddr); p += IPaddrlen; ipmove(p, ifc->lifc->local); p += IPaddrlen; hnputs(p, rport); p += 2; hnputs(p, lport); break; . 489a uchar *p; . 418a case 7: . 417d 380,383c ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ . 376,377c case 6: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD6); . 373,374c bp->rp += 2+2; /* Ignore local port */ . 371a bp->rp += IPaddrlen; /* Ignore ifc address */ . 362c bp = pullupblock(bp, UDP_USEAD7); . 360c case 7: . 32a UDP_USEAD7 = 52, .