17dd7cddfSDavid du Colombier /* 27dd7cddfSDavid du Colombier * This protocol is compatible with UDP's packet format. 37dd7cddfSDavid du Colombier * It could be done over UDP if need be. 47dd7cddfSDavid du Colombier */ 57dd7cddfSDavid du Colombier #include "u.h" 67dd7cddfSDavid du Colombier #include "../port/lib.h" 77dd7cddfSDavid du Colombier #include "mem.h" 87dd7cddfSDavid du Colombier #include "dat.h" 97dd7cddfSDavid du Colombier #include "fns.h" 107dd7cddfSDavid du Colombier #include "../port/error.h" 117dd7cddfSDavid du Colombier 127dd7cddfSDavid du Colombier #include "ip.h" 137dd7cddfSDavid du Colombier 147dd7cddfSDavid du Colombier #define DEBUG 0 157dd7cddfSDavid du Colombier #define DPRINT if(DEBUG)print 167dd7cddfSDavid du Colombier 177dd7cddfSDavid du Colombier #define SEQDIFF(a,b) ( (a)>=(b)?\ 187dd7cddfSDavid du Colombier (a)-(b):\ 197dd7cddfSDavid du Colombier 0xffffffffUL-((b)-(a)) ) 207dd7cddfSDavid du Colombier #define INSEQ(a,start,end) ( (start)<=(end)?\ 217dd7cddfSDavid du Colombier ((a)>(start)&&(a)<=(end)):\ 227dd7cddfSDavid du Colombier ((a)>(start)||(a)<=(end)) ) 237dd7cddfSDavid du Colombier #define UNACKED(r) SEQDIFF(r->sndseq, r->ackrcvd) 247dd7cddfSDavid du Colombier #define NEXTSEQ(a) ( (a)+1 == 0 ? 1 : (a)+1 ) 257dd7cddfSDavid du Colombier 267dd7cddfSDavid du Colombier enum 277dd7cddfSDavid du Colombier { 287dd7cddfSDavid du Colombier UDP_HDRSIZE = 20, /* pseudo header + udp header */ 297dd7cddfSDavid du Colombier UDP_PHDRSIZE = 12, /* pseudo header */ 307dd7cddfSDavid du Colombier UDP_RHDRSIZE = 36, /* pseudo header + udp header + rudp header */ 317dd7cddfSDavid du Colombier UDP_IPHDR = 8, /* ip header */ 327dd7cddfSDavid du Colombier IP_UDPPROTO = 254, 33dc5a79c1SDavid du Colombier UDP_USEAD7 = 52, 347dd7cddfSDavid du Colombier UDP_USEAD6 = 36, 357dd7cddfSDavid du Colombier UDP_USEAD4 = 12, 367dd7cddfSDavid du Colombier 377dd7cddfSDavid du Colombier Rudprxms = 200, 387dd7cddfSDavid du Colombier Rudptickms = 50, 397dd7cddfSDavid du Colombier Rudpmaxxmit = 10, 407dd7cddfSDavid du Colombier Maxunacked = 100, 417dd7cddfSDavid du Colombier 427dd7cddfSDavid du Colombier }; 437dd7cddfSDavid du Colombier 447dd7cddfSDavid du Colombier #define Hangupgen 0xffffffff /* used only in hangup messages */ 457dd7cddfSDavid du Colombier 467dd7cddfSDavid du Colombier typedef struct Udphdr Udphdr; 477dd7cddfSDavid du Colombier struct Udphdr 487dd7cddfSDavid du Colombier { 497dd7cddfSDavid du Colombier /* ip header */ 507dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */ 517dd7cddfSDavid du Colombier uchar tos; /* Type of service */ 527dd7cddfSDavid du Colombier uchar length[2]; /* packet length */ 537dd7cddfSDavid du Colombier uchar id[2]; /* Identification */ 547dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */ 557dd7cddfSDavid du Colombier 567dd7cddfSDavid du Colombier /* pseudo header starts here */ 577dd7cddfSDavid du Colombier uchar Unused; 587dd7cddfSDavid du Colombier uchar udpproto; /* Protocol */ 597dd7cddfSDavid du Colombier uchar udpplen[2]; /* Header plus data length */ 607dd7cddfSDavid du Colombier uchar udpsrc[4]; /* Ip source */ 617dd7cddfSDavid du Colombier uchar udpdst[4]; /* Ip destination */ 627dd7cddfSDavid du Colombier 637dd7cddfSDavid du Colombier /* udp header */ 647dd7cddfSDavid du Colombier uchar udpsport[2]; /* Source port */ 657dd7cddfSDavid du Colombier uchar udpdport[2]; /* Destination port */ 667dd7cddfSDavid du Colombier uchar udplen[2]; /* data length */ 677dd7cddfSDavid du Colombier uchar udpcksum[2]; /* Checksum */ 687dd7cddfSDavid du Colombier }; 697dd7cddfSDavid du Colombier 707dd7cddfSDavid du Colombier typedef struct Rudphdr Rudphdr; 717dd7cddfSDavid du Colombier struct Rudphdr 727dd7cddfSDavid du Colombier { 737dd7cddfSDavid du Colombier /* ip header */ 747dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */ 757dd7cddfSDavid du Colombier uchar tos; /* Type of service */ 767dd7cddfSDavid du Colombier uchar length[2]; /* packet length */ 777dd7cddfSDavid du Colombier uchar id[2]; /* Identification */ 787dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */ 797dd7cddfSDavid du Colombier 807dd7cddfSDavid du Colombier /* pseudo header starts here */ 817dd7cddfSDavid du Colombier uchar Unused; 827dd7cddfSDavid du Colombier uchar udpproto; /* Protocol */ 837dd7cddfSDavid du Colombier uchar udpplen[2]; /* Header plus data length */ 847dd7cddfSDavid du Colombier uchar udpsrc[4]; /* Ip source */ 857dd7cddfSDavid du Colombier uchar udpdst[4]; /* Ip destination */ 867dd7cddfSDavid du Colombier 877dd7cddfSDavid du Colombier /* udp header */ 887dd7cddfSDavid du Colombier uchar udpsport[2]; /* Source port */ 897dd7cddfSDavid du Colombier uchar udpdport[2]; /* Destination port */ 907dd7cddfSDavid du Colombier uchar udplen[2]; /* data length (includes rudp header) */ 917dd7cddfSDavid du Colombier uchar udpcksum[2]; /* Checksum */ 927dd7cddfSDavid du Colombier 937dd7cddfSDavid du Colombier /* rudp header */ 947dd7cddfSDavid du Colombier uchar relseq[4]; /* id of this packet (or 0) */ 957dd7cddfSDavid du Colombier uchar relsgen[4]; /* generation/time stamp */ 967dd7cddfSDavid du Colombier uchar relack[4]; /* packet being acked (or 0) */ 977dd7cddfSDavid du Colombier uchar relagen[4]; /* generation/time stamp */ 987dd7cddfSDavid du Colombier }; 997dd7cddfSDavid du Colombier 1007dd7cddfSDavid du Colombier 1017dd7cddfSDavid du Colombier /* 1027dd7cddfSDavid du Colombier * one state structure per destination 1037dd7cddfSDavid du Colombier */ 1047dd7cddfSDavid du Colombier typedef struct Reliable Reliable; 1057dd7cddfSDavid du Colombier struct Reliable 1067dd7cddfSDavid du Colombier { 1077dd7cddfSDavid du Colombier Ref; 1087dd7cddfSDavid du Colombier 1097dd7cddfSDavid du Colombier Reliable *next; 1107dd7cddfSDavid du Colombier 1117dd7cddfSDavid du Colombier uchar addr[IPaddrlen]; /* always V6 when put here */ 1127dd7cddfSDavid du Colombier ushort port; 1137dd7cddfSDavid du Colombier 1147dd7cddfSDavid du Colombier Block *unacked; /* unacked msg list */ 1157dd7cddfSDavid du Colombier Block *unackedtail; /* and its tail */ 1167dd7cddfSDavid du Colombier 1177dd7cddfSDavid du Colombier int timeout; /* time since first unacked msg sent */ 1187dd7cddfSDavid du Colombier int xmits; /* number of times first unacked msg sent */ 1197dd7cddfSDavid du Colombier 1207dd7cddfSDavid du Colombier ulong sndseq; /* next packet to be sent */ 1217dd7cddfSDavid du Colombier ulong sndgen; /* and its generation */ 1227dd7cddfSDavid du Colombier 1237dd7cddfSDavid du Colombier ulong rcvseq; /* last packet received */ 1247dd7cddfSDavid du Colombier ulong rcvgen; /* and its generation */ 1257dd7cddfSDavid du Colombier 1267dd7cddfSDavid du Colombier ulong acksent; /* last ack sent */ 1277dd7cddfSDavid du Colombier ulong ackrcvd; /* last msg for which ack was rcvd */ 1287dd7cddfSDavid du Colombier 1297dd7cddfSDavid du Colombier /* flow control */ 1307dd7cddfSDavid du Colombier QLock lock; 1317dd7cddfSDavid du Colombier Rendez vous; 1327dd7cddfSDavid du Colombier int blocked; 1337dd7cddfSDavid du Colombier }; 1347dd7cddfSDavid du Colombier 1357dd7cddfSDavid du Colombier 1367dd7cddfSDavid du Colombier 1377dd7cddfSDavid du Colombier /* MIB II counters */ 1387dd7cddfSDavid du Colombier typedef struct Rudpstats Rudpstats; 1397dd7cddfSDavid du Colombier struct Rudpstats 1407dd7cddfSDavid du Colombier { 1417dd7cddfSDavid du Colombier ulong rudpInDatagrams; 1427dd7cddfSDavid du Colombier ulong rudpNoPorts; 1437dd7cddfSDavid du Colombier ulong rudpInErrors; 1447dd7cddfSDavid du Colombier ulong rudpOutDatagrams; 1457dd7cddfSDavid du Colombier }; 1467dd7cddfSDavid du Colombier 1477dd7cddfSDavid du Colombier typedef struct Rudppriv Rudppriv; 1487dd7cddfSDavid du Colombier struct Rudppriv 1497dd7cddfSDavid du Colombier { 15080ee5cbfSDavid du Colombier Ipht ht; 1517dd7cddfSDavid du Colombier 1527dd7cddfSDavid du Colombier /* MIB counters */ 1537dd7cddfSDavid du Colombier Rudpstats ustats; 1547dd7cddfSDavid du Colombier 1557dd7cddfSDavid du Colombier /* non-MIB stats */ 1567dd7cddfSDavid du Colombier ulong csumerr; /* checksum errors */ 1577dd7cddfSDavid du Colombier ulong lenerr; /* short packet */ 1587dd7cddfSDavid du Colombier ulong rxmits; /* # of retransmissions */ 1597dd7cddfSDavid du Colombier ulong orders; /* # of out of order pkts */ 1607dd7cddfSDavid du Colombier 1617dd7cddfSDavid du Colombier /* keeping track of the ack kproc */ 1627dd7cddfSDavid du Colombier int ackprocstarted; 1637dd7cddfSDavid du Colombier QLock apl; 1647dd7cddfSDavid du Colombier }; 1657dd7cddfSDavid du Colombier 1667dd7cddfSDavid du Colombier 1677dd7cddfSDavid du Colombier static ulong generation = 0; 1687dd7cddfSDavid du Colombier static Rendez rend; 1697dd7cddfSDavid du Colombier 1707dd7cddfSDavid du Colombier /* 1717dd7cddfSDavid du Colombier * protocol specific part of Conv 1727dd7cddfSDavid du Colombier */ 1737dd7cddfSDavid du Colombier typedef struct Rudpcb Rudpcb; 1747dd7cddfSDavid du Colombier struct Rudpcb 1757dd7cddfSDavid du Colombier { 1767dd7cddfSDavid du Colombier QLock; 1777dd7cddfSDavid du Colombier uchar headers; 1787dd7cddfSDavid du Colombier uchar randdrop; 1797dd7cddfSDavid du Colombier Reliable *r; 1807dd7cddfSDavid du Colombier }; 1817dd7cddfSDavid du Colombier 1827dd7cddfSDavid du Colombier /* 1837dd7cddfSDavid du Colombier * local functions 1847dd7cddfSDavid du Colombier */ 1857dd7cddfSDavid du Colombier void relsendack(Conv*, Reliable*, int); 1867dd7cddfSDavid du Colombier int reliput(Conv*, Block*, uchar*, ushort); 1877dd7cddfSDavid du Colombier Reliable *relstate(Rudpcb*, uchar*, ushort, char*); 1887dd7cddfSDavid du Colombier void relput(Reliable*); 1897dd7cddfSDavid du Colombier void relforget(Conv *, uchar*, int, int); 1907dd7cddfSDavid du Colombier void relackproc(void *); 1917dd7cddfSDavid du Colombier void relackq(Reliable *, Block*); 1927dd7cddfSDavid du Colombier void relhangup(Conv *, Reliable*); 1937dd7cddfSDavid du Colombier void relrexmit(Conv *, Reliable*); 1947dd7cddfSDavid du Colombier void relput(Reliable*); 1953ff48bf5SDavid du Colombier void rudpkick(void *x); 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier static void 1987dd7cddfSDavid du Colombier rudpstartackproc(Proto *rudp) 1997dd7cddfSDavid du Colombier { 2007dd7cddfSDavid du Colombier Rudppriv *rpriv; 2019a747e4fSDavid du Colombier char kpname[KNAMELEN]; 2027dd7cddfSDavid du Colombier 2037dd7cddfSDavid du Colombier rpriv = rudp->priv; 2047dd7cddfSDavid du Colombier if(rpriv->ackprocstarted == 0){ 2057dd7cddfSDavid du Colombier qlock(&rpriv->apl); 2067dd7cddfSDavid du Colombier if(rpriv->ackprocstarted == 0){ 2077dd7cddfSDavid du Colombier sprint(kpname, "#I%drudpack", rudp->f->dev); 2087dd7cddfSDavid du Colombier kproc(kpname, relackproc, rudp); 2097dd7cddfSDavid du Colombier rpriv->ackprocstarted = 1; 2107dd7cddfSDavid du Colombier } 2117dd7cddfSDavid du Colombier qunlock(&rpriv->apl); 2127dd7cddfSDavid du Colombier } 2137dd7cddfSDavid du Colombier } 2147dd7cddfSDavid du Colombier 2157dd7cddfSDavid du Colombier static char* 2167dd7cddfSDavid du Colombier rudpconnect(Conv *c, char **argv, int argc) 2177dd7cddfSDavid du Colombier { 2187dd7cddfSDavid du Colombier char *e; 21980ee5cbfSDavid du Colombier Rudppriv *upriv; 2207dd7cddfSDavid du Colombier 22180ee5cbfSDavid du Colombier upriv = c->p->priv; 2227dd7cddfSDavid du Colombier rudpstartackproc(c->p); 2237dd7cddfSDavid du Colombier e = Fsstdconnect(c, argv, argc); 2247dd7cddfSDavid du Colombier Fsconnected(c, e); 22580ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c); 2267dd7cddfSDavid du Colombier 2277dd7cddfSDavid du Colombier return e; 2287dd7cddfSDavid du Colombier } 2297dd7cddfSDavid du Colombier 2307dd7cddfSDavid du Colombier 2317dd7cddfSDavid du Colombier static int 2327dd7cddfSDavid du Colombier rudpstate(Conv *c, char *state, int n) 2337dd7cddfSDavid du Colombier { 2347dd7cddfSDavid du Colombier Rudpcb *ucb; 2357dd7cddfSDavid du Colombier Reliable *r; 2367dd7cddfSDavid du Colombier int m; 2377dd7cddfSDavid du Colombier 2387dd7cddfSDavid du Colombier m = snprint(state, n, "%s", c->inuse?"Open":"Closed"); 2397dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 2407dd7cddfSDavid du Colombier qlock(ucb); 2417dd7cddfSDavid du Colombier for(r = ucb->r; r; r = r->next) 2427dd7cddfSDavid du Colombier m += snprint(state+m, n-m, " %I/%ld", r->addr, UNACKED(r)); 243*03a1fc68SDavid du Colombier m += snprint(state+m, n-m, "\n"); 2447dd7cddfSDavid du Colombier qunlock(ucb); 2457dd7cddfSDavid du Colombier return m; 2467dd7cddfSDavid du Colombier } 2477dd7cddfSDavid du Colombier 2487dd7cddfSDavid du Colombier static char* 2497dd7cddfSDavid du Colombier rudpannounce(Conv *c, char** argv, int argc) 2507dd7cddfSDavid du Colombier { 2517dd7cddfSDavid du Colombier char *e; 25280ee5cbfSDavid du Colombier Rudppriv *upriv; 2537dd7cddfSDavid du Colombier 25480ee5cbfSDavid du Colombier upriv = c->p->priv; 2557dd7cddfSDavid du Colombier rudpstartackproc(c->p); 2567dd7cddfSDavid du Colombier e = Fsstdannounce(c, argv, argc); 2577dd7cddfSDavid du Colombier if(e != nil) 2587dd7cddfSDavid du Colombier return e; 2597dd7cddfSDavid du Colombier Fsconnected(c, nil); 26080ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c); 2617dd7cddfSDavid du Colombier 2627dd7cddfSDavid du Colombier return nil; 2637dd7cddfSDavid du Colombier } 2647dd7cddfSDavid du Colombier 2657dd7cddfSDavid du Colombier static void 2667dd7cddfSDavid du Colombier rudpcreate(Conv *c) 2677dd7cddfSDavid du Colombier { 2683ff48bf5SDavid du Colombier c->rq = qopen(64*1024, Qmsg, 0, 0); 2693ff48bf5SDavid du Colombier c->wq = qopen(64*1024, Qkick, rudpkick, c); 2707dd7cddfSDavid du Colombier } 2717dd7cddfSDavid du Colombier 2727dd7cddfSDavid du Colombier static void 2737dd7cddfSDavid du Colombier rudpclose(Conv *c) 2747dd7cddfSDavid du Colombier { 2757dd7cddfSDavid du Colombier Rudpcb *ucb; 2767dd7cddfSDavid du Colombier Reliable *r, *nr; 27780ee5cbfSDavid du Colombier Rudppriv *upriv; 27880ee5cbfSDavid du Colombier 27980ee5cbfSDavid du Colombier upriv = c->p->priv; 28080ee5cbfSDavid du Colombier iphtrem(&upriv->ht, c); 2817dd7cddfSDavid du Colombier 2827dd7cddfSDavid du Colombier /* force out any delayed acks */ 2837dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 2847dd7cddfSDavid du Colombier qlock(ucb); 2857dd7cddfSDavid du Colombier for(r = ucb->r; r; r = r->next){ 2867dd7cddfSDavid du Colombier if(r->acksent != r->rcvseq) 2877dd7cddfSDavid du Colombier relsendack(c, r, 0); 2887dd7cddfSDavid du Colombier } 2897dd7cddfSDavid du Colombier qunlock(ucb); 2907dd7cddfSDavid du Colombier 2917dd7cddfSDavid du Colombier qclose(c->rq); 2927dd7cddfSDavid du Colombier qclose(c->wq); 2937dd7cddfSDavid du Colombier qclose(c->eq); 2947dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 2957dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr); 2967dd7cddfSDavid du Colombier c->lport = 0; 2977dd7cddfSDavid du Colombier c->rport = 0; 2987dd7cddfSDavid du Colombier 2997dd7cddfSDavid du Colombier ucb->headers = 0; 3007dd7cddfSDavid du Colombier ucb->randdrop = 0; 3017dd7cddfSDavid du Colombier qlock(ucb); 3027dd7cddfSDavid du Colombier for(r = ucb->r; r; r = nr){ 3037dd7cddfSDavid du Colombier if(r->acksent != r->rcvseq) 3047dd7cddfSDavid du Colombier relsendack(c, r, 0); 3057dd7cddfSDavid du Colombier nr = r->next; 3067dd7cddfSDavid du Colombier relhangup(c, r); 3077dd7cddfSDavid du Colombier relput(r); 3087dd7cddfSDavid du Colombier } 3097dd7cddfSDavid du Colombier ucb->r = 0; 3107dd7cddfSDavid du Colombier 3117dd7cddfSDavid du Colombier qunlock(ucb); 3127dd7cddfSDavid du Colombier } 3137dd7cddfSDavid du Colombier 3147dd7cddfSDavid du Colombier /* 3157dd7cddfSDavid du Colombier * randomly don't send packets 3167dd7cddfSDavid du Colombier */ 3177dd7cddfSDavid du Colombier static void 3187dd7cddfSDavid du Colombier doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl, int tos) 3197dd7cddfSDavid du Colombier { 3207dd7cddfSDavid du Colombier Rudpcb *ucb; 3217dd7cddfSDavid du Colombier 3227dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 3237dd7cddfSDavid du Colombier if(ucb->randdrop && nrand(100) < ucb->randdrop) 3247dd7cddfSDavid du Colombier freeblist(bp); 3257dd7cddfSDavid du Colombier else 326a6a9e072SDavid du Colombier ipoput4(f, bp, x, ttl, tos, nil); 3277dd7cddfSDavid du Colombier } 3287dd7cddfSDavid du Colombier 3297dd7cddfSDavid du Colombier int 3307dd7cddfSDavid du Colombier flow(void *v) 3317dd7cddfSDavid du Colombier { 3327dd7cddfSDavid du Colombier Reliable *r = v; 3337dd7cddfSDavid du Colombier 3347dd7cddfSDavid du Colombier return UNACKED(r) <= Maxunacked; 3357dd7cddfSDavid du Colombier } 3367dd7cddfSDavid du Colombier 3377dd7cddfSDavid du Colombier void 3383ff48bf5SDavid du Colombier rudpkick(void *x) 3397dd7cddfSDavid du Colombier { 3403ff48bf5SDavid du Colombier Conv *c = x; 3417dd7cddfSDavid du Colombier Udphdr *uh; 3427dd7cddfSDavid du Colombier ushort rport; 3437dd7cddfSDavid du Colombier uchar laddr[IPaddrlen], raddr[IPaddrlen]; 3447dd7cddfSDavid du Colombier Block *bp; 3457dd7cddfSDavid du Colombier Rudpcb *ucb; 3467dd7cddfSDavid du Colombier Rudphdr *rh; 3477dd7cddfSDavid du Colombier Reliable *r; 3487dd7cddfSDavid du Colombier int dlen, ptcllen; 3497dd7cddfSDavid du Colombier Rudppriv *upriv; 3507dd7cddfSDavid du Colombier Fs *f; 3517dd7cddfSDavid du Colombier 3527dd7cddfSDavid du Colombier upriv = c->p->priv; 3537dd7cddfSDavid du Colombier f = c->p->f; 3547dd7cddfSDavid du Colombier 3557dd7cddfSDavid du Colombier netlog(c->p->f, Logrudp, "rudp: kick\n"); 3567dd7cddfSDavid du Colombier bp = qget(c->wq); 3577dd7cddfSDavid du Colombier if(bp == nil) 3587dd7cddfSDavid du Colombier return; 3597dd7cddfSDavid du Colombier 3607dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 3617dd7cddfSDavid du Colombier switch(ucb->headers) { 362dc5a79c1SDavid du Colombier case 7: 363dc5a79c1SDavid du Colombier /* get user specified addresses */ 364dc5a79c1SDavid du Colombier bp = pullupblock(bp, UDP_USEAD7); 365dc5a79c1SDavid du Colombier if(bp == nil) 366dc5a79c1SDavid du Colombier return; 367dc5a79c1SDavid du Colombier ipmove(raddr, bp->rp); 368dc5a79c1SDavid du Colombier bp->rp += IPaddrlen; 369dc5a79c1SDavid du Colombier ipmove(laddr, bp->rp); 370dc5a79c1SDavid du Colombier bp->rp += IPaddrlen; 371dc5a79c1SDavid du Colombier /* pick interface closest to dest */ 372dc5a79c1SDavid du Colombier if(ipforme(f, laddr) != Runi) 373dc5a79c1SDavid du Colombier findlocalip(f, laddr, raddr); 374dc5a79c1SDavid du Colombier bp->rp += IPaddrlen; /* Ignore ifc address */ 375dc5a79c1SDavid du Colombier rport = nhgets(bp->rp); 376dc5a79c1SDavid du Colombier bp->rp += 2+2; /* Ignore local port */ 377dc5a79c1SDavid du Colombier break; 378f2c197d9SDavid du Colombier case 6: /* OBS */ 3797dd7cddfSDavid du Colombier /* get user specified addresses */ 3807dd7cddfSDavid du Colombier bp = pullupblock(bp, UDP_USEAD6); 3817dd7cddfSDavid du Colombier if(bp == nil) 3827dd7cddfSDavid du Colombier return; 3837dd7cddfSDavid du Colombier ipmove(raddr, bp->rp); 3847dd7cddfSDavid du Colombier bp->rp += IPaddrlen; 3857dd7cddfSDavid du Colombier ipmove(laddr, bp->rp); 3867dd7cddfSDavid du Colombier bp->rp += IPaddrlen; 3877dd7cddfSDavid du Colombier /* pick interface closest to dest */ 3887dd7cddfSDavid du Colombier if(ipforme(f, laddr) != Runi) 3897dd7cddfSDavid du Colombier findlocalip(f, laddr, raddr); 3907dd7cddfSDavid du Colombier rport = nhgets(bp->rp); 3917dd7cddfSDavid du Colombier 3927dd7cddfSDavid du Colombier bp->rp += 4; /* Igonore local port */ 3937dd7cddfSDavid du Colombier break; 3947dd7cddfSDavid du Colombier default: 3957dd7cddfSDavid du Colombier ipmove(raddr, c->raddr); 3967dd7cddfSDavid du Colombier ipmove(laddr, c->laddr); 3977dd7cddfSDavid du Colombier rport = c->rport; 3987dd7cddfSDavid du Colombier 3997dd7cddfSDavid du Colombier break; 4007dd7cddfSDavid du Colombier } 4017dd7cddfSDavid du Colombier 4027dd7cddfSDavid du Colombier dlen = blocklen(bp); 4037dd7cddfSDavid du Colombier 4047dd7cddfSDavid du Colombier /* Make space to fit rudp & ip header */ 4057dd7cddfSDavid du Colombier bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE); 4067dd7cddfSDavid du Colombier if(bp == nil) 4077dd7cddfSDavid du Colombier return; 4087dd7cddfSDavid du Colombier 4097dd7cddfSDavid du Colombier uh = (Udphdr *)(bp->rp); 4103ff48bf5SDavid du Colombier uh->vihl = IP_VER4; 4117dd7cddfSDavid du Colombier 4127dd7cddfSDavid du Colombier rh = (Rudphdr*)uh; 4137dd7cddfSDavid du Colombier 4147dd7cddfSDavid du Colombier ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE); 4157dd7cddfSDavid du Colombier uh->Unused = 0; 4167dd7cddfSDavid du Colombier uh->udpproto = IP_UDPPROTO; 4177dd7cddfSDavid du Colombier uh->frag[0] = 0; 4187dd7cddfSDavid du Colombier uh->frag[1] = 0; 4197dd7cddfSDavid du Colombier hnputs(uh->udpplen, ptcllen); 4207dd7cddfSDavid du Colombier switch(ucb->headers){ 421f2c197d9SDavid du Colombier case 6: /* OBS */ 422dc5a79c1SDavid du Colombier case 7: 4237dd7cddfSDavid du Colombier v6tov4(uh->udpdst, raddr); 4247dd7cddfSDavid du Colombier hnputs(uh->udpdport, rport); 4257dd7cddfSDavid du Colombier v6tov4(uh->udpsrc, laddr); 4267dd7cddfSDavid du Colombier break; 4277dd7cddfSDavid du Colombier default: 4287dd7cddfSDavid du Colombier v6tov4(uh->udpdst, c->raddr); 4297dd7cddfSDavid du Colombier hnputs(uh->udpdport, c->rport); 4307dd7cddfSDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0) 4317dd7cddfSDavid du Colombier findlocalip(f, c->laddr, c->raddr); 4327dd7cddfSDavid du Colombier v6tov4(uh->udpsrc, c->laddr); 4337dd7cddfSDavid du Colombier break; 4347dd7cddfSDavid du Colombier } 4357dd7cddfSDavid du Colombier hnputs(uh->udpsport, c->lport); 4367dd7cddfSDavid du Colombier hnputs(uh->udplen, ptcllen); 4377dd7cddfSDavid du Colombier uh->udpcksum[0] = 0; 4387dd7cddfSDavid du Colombier uh->udpcksum[1] = 0; 4397dd7cddfSDavid du Colombier 4407dd7cddfSDavid du Colombier qlock(ucb); 4417dd7cddfSDavid du Colombier r = relstate(ucb, raddr, rport, "kick"); 4427dd7cddfSDavid du Colombier r->sndseq = NEXTSEQ(r->sndseq); 4437dd7cddfSDavid du Colombier hnputl(rh->relseq, r->sndseq); 4447dd7cddfSDavid du Colombier hnputl(rh->relsgen, r->sndgen); 4457dd7cddfSDavid du Colombier 4467dd7cddfSDavid du Colombier hnputl(rh->relack, r->rcvseq); /* ACK last rcvd packet */ 4477dd7cddfSDavid du Colombier hnputl(rh->relagen, r->rcvgen); 4487dd7cddfSDavid du Colombier 4497dd7cddfSDavid du Colombier if(r->rcvseq != r->acksent) 4507dd7cddfSDavid du Colombier r->acksent = r->rcvseq; 4517dd7cddfSDavid du Colombier 4527dd7cddfSDavid du Colombier hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE)); 4537dd7cddfSDavid du Colombier 4547dd7cddfSDavid du Colombier relackq(r, bp); 4557dd7cddfSDavid du Colombier qunlock(ucb); 4567dd7cddfSDavid du Colombier 4577dd7cddfSDavid du Colombier upriv->ustats.rudpOutDatagrams++; 4587dd7cddfSDavid du Colombier 4597dd7cddfSDavid du Colombier DPRINT("sent: %lud/%lud, %lud/%lud\n", 4607dd7cddfSDavid du Colombier r->sndseq, r->sndgen, r->rcvseq, r->rcvgen); 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier doipoput(c, f, bp, 0, c->ttl, c->tos); 4637dd7cddfSDavid du Colombier 4647dd7cddfSDavid du Colombier if(waserror()) { 4657dd7cddfSDavid du Colombier relput(r); 4667dd7cddfSDavid du Colombier qunlock(&r->lock); 4677dd7cddfSDavid du Colombier nexterror(); 4687dd7cddfSDavid du Colombier } 4697dd7cddfSDavid du Colombier 4707dd7cddfSDavid du Colombier /* flow control of sorts */ 4717dd7cddfSDavid du Colombier qlock(&r->lock); 4727dd7cddfSDavid du Colombier if(UNACKED(r) > Maxunacked){ 4737dd7cddfSDavid du Colombier r->blocked = 1; 4747dd7cddfSDavid du Colombier sleep(&r->vous, flow, r); 4757dd7cddfSDavid du Colombier r->blocked = 0; 4767dd7cddfSDavid du Colombier } 4777dd7cddfSDavid du Colombier 4787dd7cddfSDavid du Colombier qunlock(&r->lock); 4797dd7cddfSDavid du Colombier relput(r); 4807dd7cddfSDavid du Colombier poperror(); 4817dd7cddfSDavid du Colombier } 4827dd7cddfSDavid du Colombier 4837dd7cddfSDavid du Colombier void 4849a747e4fSDavid du Colombier rudpiput(Proto *rudp, Ipifc *ifc, Block *bp) 4857dd7cddfSDavid du Colombier { 4867dd7cddfSDavid du Colombier int len, olen, ottl; 4877dd7cddfSDavid du Colombier Udphdr *uh; 48880ee5cbfSDavid du Colombier Conv *c; 4897dd7cddfSDavid du Colombier Rudpcb *ucb; 4907dd7cddfSDavid du Colombier uchar raddr[IPaddrlen], laddr[IPaddrlen]; 4917dd7cddfSDavid du Colombier ushort rport, lport; 4927dd7cddfSDavid du Colombier Rudppriv *upriv; 4937dd7cddfSDavid du Colombier Fs *f; 494dc5a79c1SDavid du Colombier uchar *p; 4957dd7cddfSDavid du Colombier 4967dd7cddfSDavid du Colombier upriv = rudp->priv; 4977dd7cddfSDavid du Colombier f = rudp->f; 4987dd7cddfSDavid du Colombier 4997dd7cddfSDavid du Colombier upriv->ustats.rudpInDatagrams++; 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier uh = (Udphdr*)(bp->rp); 5027dd7cddfSDavid du Colombier 5037dd7cddfSDavid du Colombier /* Put back pseudo header for checksum 5047dd7cddfSDavid du Colombier * (remember old values for icmpnoconv()) 5057dd7cddfSDavid du Colombier */ 5067dd7cddfSDavid du Colombier ottl = uh->Unused; 5077dd7cddfSDavid du Colombier uh->Unused = 0; 5087dd7cddfSDavid du Colombier len = nhgets(uh->udplen); 5097dd7cddfSDavid du Colombier olen = nhgets(uh->udpplen); 5107dd7cddfSDavid du Colombier hnputs(uh->udpplen, len); 5117dd7cddfSDavid du Colombier 5127dd7cddfSDavid du Colombier v4tov6(raddr, uh->udpsrc); 5137dd7cddfSDavid du Colombier v4tov6(laddr, uh->udpdst); 5147dd7cddfSDavid du Colombier lport = nhgets(uh->udpdport); 5157dd7cddfSDavid du Colombier rport = nhgets(uh->udpsport); 5167dd7cddfSDavid du Colombier 5177dd7cddfSDavid du Colombier if(nhgets(uh->udpcksum)) { 5187dd7cddfSDavid du Colombier if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { 5197dd7cddfSDavid du Colombier upriv->ustats.rudpInErrors++; 5207dd7cddfSDavid du Colombier upriv->csumerr++; 5217dd7cddfSDavid du Colombier netlog(f, Logrudp, "rudp: checksum error %I\n", raddr); 5227dd7cddfSDavid du Colombier DPRINT("rudp: checksum error %I\n", raddr); 5237dd7cddfSDavid du Colombier freeblist(bp); 5247dd7cddfSDavid du Colombier return; 5257dd7cddfSDavid du Colombier } 5267dd7cddfSDavid du Colombier } 5277dd7cddfSDavid du Colombier 5287dd7cddfSDavid du Colombier qlock(rudp); 5297dd7cddfSDavid du Colombier 53080ee5cbfSDavid du Colombier c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); 53180ee5cbfSDavid du Colombier if(c == nil){ 53280ee5cbfSDavid du Colombier /* no converstation found */ 5337dd7cddfSDavid du Colombier upriv->ustats.rudpNoPorts++; 53480ee5cbfSDavid du Colombier qunlock(rudp); 53580ee5cbfSDavid du Colombier netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, 5367dd7cddfSDavid du Colombier laddr, lport); 5377dd7cddfSDavid du Colombier uh->Unused = ottl; 5387dd7cddfSDavid du Colombier hnputs(uh->udpplen, olen); 5397dd7cddfSDavid du Colombier icmpnoconv(f, bp); 5407dd7cddfSDavid du Colombier freeblist(bp); 5417dd7cddfSDavid du Colombier return; 5427dd7cddfSDavid du Colombier } 5437dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 5447dd7cddfSDavid du Colombier qlock(ucb); 5457dd7cddfSDavid du Colombier qunlock(rudp); 5467dd7cddfSDavid du Colombier 5477dd7cddfSDavid du Colombier if(reliput(c, bp, raddr, rport) < 0){ 5487dd7cddfSDavid du Colombier qunlock(ucb); 5497dd7cddfSDavid du Colombier freeb(bp); 5507dd7cddfSDavid du Colombier return; 5517dd7cddfSDavid du Colombier } 5527dd7cddfSDavid du Colombier 5537dd7cddfSDavid du Colombier /* 5547dd7cddfSDavid du Colombier * Trim the packet down to data size 5557dd7cddfSDavid du Colombier */ 5567dd7cddfSDavid du Colombier 5577dd7cddfSDavid du Colombier len -= (UDP_RHDRSIZE-UDP_PHDRSIZE); 5587dd7cddfSDavid du Colombier bp = trimblock(bp, UDP_IPHDR+UDP_RHDRSIZE, len); 5597dd7cddfSDavid du Colombier if(bp == nil) { 5607dd7cddfSDavid du Colombier netlog(f, Logrudp, "rudp: len err %I.%d -> %I.%d\n", 5617dd7cddfSDavid du Colombier raddr, rport, laddr, lport); 5627dd7cddfSDavid du Colombier DPRINT("rudp: len err %I.%d -> %I.%d\n", 5637dd7cddfSDavid du Colombier raddr, rport, laddr, lport); 5647dd7cddfSDavid du Colombier upriv->lenerr++; 5657dd7cddfSDavid du Colombier return; 5667dd7cddfSDavid du Colombier } 5677dd7cddfSDavid du Colombier 5687dd7cddfSDavid du Colombier netlog(f, Logrudpmsg, "rudp: %I.%d -> %I.%d l %d\n", 5697dd7cddfSDavid du Colombier raddr, rport, laddr, lport, len); 5707dd7cddfSDavid du Colombier 5717dd7cddfSDavid du Colombier switch(ucb->headers){ 572dc5a79c1SDavid du Colombier case 7: 573dc5a79c1SDavid du Colombier /* pass the src address */ 574dc5a79c1SDavid du Colombier bp = padblock(bp, UDP_USEAD7); 575dc5a79c1SDavid du Colombier p = bp->rp; 576dc5a79c1SDavid du Colombier ipmove(p, raddr); p += IPaddrlen; 577dc5a79c1SDavid du Colombier ipmove(p, laddr); p += IPaddrlen; 578dc5a79c1SDavid du Colombier ipmove(p, ifc->lifc->local); p += IPaddrlen; 579dc5a79c1SDavid du Colombier hnputs(p, rport); p += 2; 580dc5a79c1SDavid du Colombier hnputs(p, lport); 581dc5a79c1SDavid du Colombier break; 582f2c197d9SDavid du Colombier case 6: /* OBS */ 5837dd7cddfSDavid du Colombier /* pass the src address */ 5847dd7cddfSDavid du Colombier bp = padblock(bp, UDP_USEAD6); 585dc5a79c1SDavid du Colombier p = bp->rp; 586dc5a79c1SDavid du Colombier ipmove(p, raddr); p += IPaddrlen; 587dc5a79c1SDavid du Colombier ipmove(p, ipforme(f, laddr)==Runi ? laddr : ifc->lifc->local); p += IPaddrlen; 588dc5a79c1SDavid du Colombier hnputs(p, rport); p += 2; 589dc5a79c1SDavid du Colombier hnputs(p, lport); 5907dd7cddfSDavid du Colombier break; 5917dd7cddfSDavid du Colombier default: 5927dd7cddfSDavid du Colombier /* connection oriented rudp */ 5937dd7cddfSDavid du Colombier if(ipcmp(c->raddr, IPnoaddr) == 0){ 5947dd7cddfSDavid du Colombier /* save the src address in the conversation */ 5957dd7cddfSDavid du Colombier ipmove(c->raddr, raddr); 5967dd7cddfSDavid du Colombier c->rport = rport; 5977dd7cddfSDavid du Colombier 5987dd7cddfSDavid du Colombier /* reply with the same ip address (if not broadcast) */ 5997dd7cddfSDavid du Colombier if(ipforme(f, laddr) == Runi) 6007dd7cddfSDavid du Colombier ipmove(c->laddr, laddr); 6017dd7cddfSDavid du Colombier else 6029a747e4fSDavid du Colombier v4tov6(c->laddr, ifc->lifc->local); 6037dd7cddfSDavid du Colombier } 6047dd7cddfSDavid du Colombier break; 6057dd7cddfSDavid du Colombier } 6067dd7cddfSDavid du Colombier if(bp->next) 6077dd7cddfSDavid du Colombier bp = concatblock(bp); 6087dd7cddfSDavid du Colombier 6097dd7cddfSDavid du Colombier if(qfull(c->rq)) { 6107dd7cddfSDavid du Colombier netlog(f, Logrudp, "rudp: qfull %I.%d -> %I.%d\n", raddr, rport, 6117dd7cddfSDavid du Colombier laddr, lport); 6127dd7cddfSDavid du Colombier freeblist(bp); 6137dd7cddfSDavid du Colombier } 6147dd7cddfSDavid du Colombier else 6157dd7cddfSDavid du Colombier qpass(c->rq, bp); 6167dd7cddfSDavid du Colombier 6177dd7cddfSDavid du Colombier qunlock(ucb); 6187dd7cddfSDavid du Colombier } 6197dd7cddfSDavid du Colombier 6207dd7cddfSDavid du Colombier static char *rudpunknown = "unknown rudp ctl request"; 6217dd7cddfSDavid du Colombier 6227dd7cddfSDavid du Colombier char* 6237dd7cddfSDavid du Colombier rudpctl(Conv *c, char **f, int n) 6247dd7cddfSDavid du Colombier { 6257dd7cddfSDavid du Colombier Rudpcb *ucb; 6267dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; 6277dd7cddfSDavid du Colombier int x; 6287dd7cddfSDavid du Colombier 6297dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 6307dd7cddfSDavid du Colombier if(n < 1) 6317dd7cddfSDavid du Colombier return rudpunknown; 6327dd7cddfSDavid du Colombier 633dc5a79c1SDavid du Colombier if(strcmp(f[0], "headers++4") == 0){ 634f2c197d9SDavid du Colombier ucb->headers = 7; /* new headers format */ 6357dd7cddfSDavid du Colombier return nil; 636f2c197d9SDavid du Colombier } else if(strcmp(f[0], "headers") == 0){ /* OBS */ 6377dd7cddfSDavid du Colombier ucb->headers = 6; 6387dd7cddfSDavid du Colombier return nil; 6397dd7cddfSDavid du Colombier } else if(strcmp(f[0], "hangup") == 0){ 6407dd7cddfSDavid du Colombier if(n < 3) 6417dd7cddfSDavid du Colombier return "bad syntax"; 6427dd7cddfSDavid du Colombier parseip(ip, f[1]); 6437dd7cddfSDavid du Colombier x = atoi(f[2]); 6447dd7cddfSDavid du Colombier qlock(ucb); 6457dd7cddfSDavid du Colombier relforget(c, ip, x, 1); 6467dd7cddfSDavid du Colombier qunlock(ucb); 6477dd7cddfSDavid du Colombier return nil; 6487dd7cddfSDavid du Colombier } else if(strcmp(f[0], "randdrop") == 0){ 6497dd7cddfSDavid du Colombier x = 10; /* default is 10% */ 6507dd7cddfSDavid du Colombier if(n > 1) 6517dd7cddfSDavid du Colombier x = atoi(f[1]); 6527dd7cddfSDavid du Colombier if(x > 100 || x < 0) 6537dd7cddfSDavid du Colombier return "illegal rudp drop rate"; 6547dd7cddfSDavid du Colombier ucb->randdrop = x; 6557dd7cddfSDavid du Colombier return nil; 6567dd7cddfSDavid du Colombier } 6577dd7cddfSDavid du Colombier return rudpunknown; 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier 6607dd7cddfSDavid du Colombier void 6617dd7cddfSDavid du Colombier rudpadvise(Proto *rudp, Block *bp, char *msg) 6627dd7cddfSDavid du Colombier { 6637dd7cddfSDavid du Colombier Udphdr *h; 6647dd7cddfSDavid du Colombier uchar source[IPaddrlen], dest[IPaddrlen]; 6657dd7cddfSDavid du Colombier ushort psource, pdest; 6667dd7cddfSDavid du Colombier Conv *s, **p; 6677dd7cddfSDavid du Colombier 6687dd7cddfSDavid du Colombier h = (Udphdr*)(bp->rp); 6697dd7cddfSDavid du Colombier 6707dd7cddfSDavid du Colombier v4tov6(dest, h->udpdst); 6717dd7cddfSDavid du Colombier v4tov6(source, h->udpsrc); 6727dd7cddfSDavid du Colombier psource = nhgets(h->udpsport); 6737dd7cddfSDavid du Colombier pdest = nhgets(h->udpdport); 6747dd7cddfSDavid du Colombier 6757dd7cddfSDavid du Colombier /* Look for a connection */ 6767dd7cddfSDavid du Colombier for(p = rudp->conv; *p; p++) { 6777dd7cddfSDavid du Colombier s = *p; 6787dd7cddfSDavid du Colombier if(s->rport == pdest) 6797dd7cddfSDavid du Colombier if(s->lport == psource) 6807dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dest) == 0) 6817dd7cddfSDavid du Colombier if(ipcmp(s->laddr, source) == 0){ 6827dd7cddfSDavid du Colombier qhangup(s->rq, msg); 6837dd7cddfSDavid du Colombier qhangup(s->wq, msg); 6847dd7cddfSDavid du Colombier break; 6857dd7cddfSDavid du Colombier } 6867dd7cddfSDavid du Colombier } 6877dd7cddfSDavid du Colombier freeblist(bp); 6887dd7cddfSDavid du Colombier } 6897dd7cddfSDavid du Colombier 6907dd7cddfSDavid du Colombier int 6917dd7cddfSDavid du Colombier rudpstats(Proto *rudp, char *buf, int len) 6927dd7cddfSDavid du Colombier { 6937dd7cddfSDavid du Colombier Rudppriv *upriv; 6947dd7cddfSDavid du Colombier 6957dd7cddfSDavid du Colombier upriv = rudp->priv; 6967dd7cddfSDavid du Colombier return snprint(buf, len, "%lud %lud %lud %lud %lud %lud\n", 6977dd7cddfSDavid du Colombier upriv->ustats.rudpInDatagrams, 6987dd7cddfSDavid du Colombier upriv->ustats.rudpNoPorts, 6997dd7cddfSDavid du Colombier upriv->ustats.rudpInErrors, 7007dd7cddfSDavid du Colombier upriv->ustats.rudpOutDatagrams, 7017dd7cddfSDavid du Colombier upriv->rxmits, 7027dd7cddfSDavid du Colombier upriv->orders); 7037dd7cddfSDavid du Colombier } 7047dd7cddfSDavid du Colombier 7057dd7cddfSDavid du Colombier void 7067dd7cddfSDavid du Colombier rudpinit(Fs *fs) 7077dd7cddfSDavid du Colombier { 7087dd7cddfSDavid du Colombier 7097dd7cddfSDavid du Colombier Proto *rudp; 7107dd7cddfSDavid du Colombier 7117dd7cddfSDavid du Colombier rudp = smalloc(sizeof(Proto)); 7127dd7cddfSDavid du Colombier rudp->priv = smalloc(sizeof(Rudppriv)); 7137dd7cddfSDavid du Colombier rudp->name = "rudp"; 7147dd7cddfSDavid du Colombier rudp->connect = rudpconnect; 7157dd7cddfSDavid du Colombier rudp->announce = rudpannounce; 7167dd7cddfSDavid du Colombier rudp->ctl = rudpctl; 7177dd7cddfSDavid du Colombier rudp->state = rudpstate; 7187dd7cddfSDavid du Colombier rudp->create = rudpcreate; 7197dd7cddfSDavid du Colombier rudp->close = rudpclose; 7207dd7cddfSDavid du Colombier rudp->rcv = rudpiput; 7217dd7cddfSDavid du Colombier rudp->advise = rudpadvise; 7227dd7cddfSDavid du Colombier rudp->stats = rudpstats; 7237dd7cddfSDavid du Colombier rudp->ipproto = IP_UDPPROTO; 7247dd7cddfSDavid du Colombier rudp->nc = 16; 7257dd7cddfSDavid du Colombier rudp->ptclsize = sizeof(Rudpcb); 7267dd7cddfSDavid du Colombier 7277dd7cddfSDavid du Colombier Fsproto(fs, rudp); 7287dd7cddfSDavid du Colombier } 7297dd7cddfSDavid du Colombier 7307dd7cddfSDavid du Colombier /*********************************************/ 7317dd7cddfSDavid du Colombier /* Here starts the reliable helper functions */ 7327dd7cddfSDavid du Colombier /*********************************************/ 7337dd7cddfSDavid du Colombier /* 7347dd7cddfSDavid du Colombier * Enqueue a copy of an unacked block for possible retransmissions 7357dd7cddfSDavid du Colombier */ 7367dd7cddfSDavid du Colombier void 7377dd7cddfSDavid du Colombier relackq(Reliable *r, Block *bp) 7387dd7cddfSDavid du Colombier { 7397dd7cddfSDavid du Colombier Block *np; 7407dd7cddfSDavid du Colombier 7417dd7cddfSDavid du Colombier np = copyblock(bp, blocklen(bp)); 7427dd7cddfSDavid du Colombier if(r->unacked) 7437dd7cddfSDavid du Colombier r->unackedtail->list = np; 7447dd7cddfSDavid du Colombier else { 7457dd7cddfSDavid du Colombier /* restart timer */ 7467dd7cddfSDavid du Colombier r->timeout = 0; 7477dd7cddfSDavid du Colombier r->xmits = 1; 7487dd7cddfSDavid du Colombier r->unacked = np; 7497dd7cddfSDavid du Colombier } 7507dd7cddfSDavid du Colombier r->unackedtail = np; 7517dd7cddfSDavid du Colombier np->list = nil; 7527dd7cddfSDavid du Colombier } 7537dd7cddfSDavid du Colombier 7547dd7cddfSDavid du Colombier /* 7557dd7cddfSDavid du Colombier * retransmit unacked blocks 7567dd7cddfSDavid du Colombier */ 7577dd7cddfSDavid du Colombier void 7587dd7cddfSDavid du Colombier relackproc(void *a) 7597dd7cddfSDavid du Colombier { 7607dd7cddfSDavid du Colombier Rudpcb *ucb; 7617dd7cddfSDavid du Colombier Proto *rudp; 7627dd7cddfSDavid du Colombier Reliable *r; 7637dd7cddfSDavid du Colombier Conv **s, *c; 7647dd7cddfSDavid du Colombier 7657dd7cddfSDavid du Colombier rudp = (Proto *)a; 7667dd7cddfSDavid du Colombier 7677dd7cddfSDavid du Colombier loop: 768dc5a79c1SDavid du Colombier tsleep(&up->sleep, return0, 0, Rudptickms); 7697dd7cddfSDavid du Colombier 7707dd7cddfSDavid du Colombier for(s = rudp->conv; *s; s++) { 7717dd7cddfSDavid du Colombier c = *s; 7727dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 7737dd7cddfSDavid du Colombier qlock(ucb); 7747dd7cddfSDavid du Colombier 7757dd7cddfSDavid du Colombier for(r = ucb->r; r; r = r->next) { 7767dd7cddfSDavid du Colombier if(r->unacked != nil){ 7777dd7cddfSDavid du Colombier r->timeout += Rudptickms; 7787dd7cddfSDavid du Colombier if(r->timeout > Rudprxms*r->xmits) 7797dd7cddfSDavid du Colombier relrexmit(c, r); 7807dd7cddfSDavid du Colombier } 7817dd7cddfSDavid du Colombier if(r->acksent != r->rcvseq) 7827dd7cddfSDavid du Colombier relsendack(c, r, 0); 7837dd7cddfSDavid du Colombier } 7847dd7cddfSDavid du Colombier qunlock(ucb); 7857dd7cddfSDavid du Colombier } 7867dd7cddfSDavid du Colombier goto loop; 7877dd7cddfSDavid du Colombier } 7887dd7cddfSDavid du Colombier 7897dd7cddfSDavid du Colombier /* 7907dd7cddfSDavid du Colombier * get the state record for a conversation 7917dd7cddfSDavid du Colombier */ 7927dd7cddfSDavid du Colombier Reliable* 7937dd7cddfSDavid du Colombier relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from) 7947dd7cddfSDavid du Colombier { 7957dd7cddfSDavid du Colombier Reliable *r, **l; 7967dd7cddfSDavid du Colombier 7977dd7cddfSDavid du Colombier l = &ucb->r; 7987dd7cddfSDavid du Colombier for(r = *l; r; r = *l){ 7997dd7cddfSDavid du Colombier if(memcmp(addr, r->addr, IPaddrlen) == 0 && 8007dd7cddfSDavid du Colombier port == r->port) 8017dd7cddfSDavid du Colombier break; 8027dd7cddfSDavid du Colombier l = &r->next; 8037dd7cddfSDavid du Colombier } 8047dd7cddfSDavid du Colombier 8057dd7cddfSDavid du Colombier /* no state for this addr/port, create some */ 8067dd7cddfSDavid du Colombier if(r == nil){ 8077dd7cddfSDavid du Colombier while(generation == 0) 8087dd7cddfSDavid du Colombier generation = rand(); 8097dd7cddfSDavid du Colombier 8107dd7cddfSDavid du Colombier DPRINT("from %s new state %lud for %I!%ud\n", 8117dd7cddfSDavid du Colombier from, generation, addr, port); 8127dd7cddfSDavid du Colombier 8137dd7cddfSDavid du Colombier r = smalloc(sizeof(Reliable)); 8147dd7cddfSDavid du Colombier memmove(r->addr, addr, IPaddrlen); 8157dd7cddfSDavid du Colombier r->port = port; 8167dd7cddfSDavid du Colombier r->unacked = 0; 8177dd7cddfSDavid du Colombier if(generation == Hangupgen) 8187dd7cddfSDavid du Colombier generation++; 8197dd7cddfSDavid du Colombier r->sndgen = generation++; 8207dd7cddfSDavid du Colombier r->sndseq = 0; 8217dd7cddfSDavid du Colombier r->ackrcvd = 0; 8227dd7cddfSDavid du Colombier r->rcvgen = 0; 8237dd7cddfSDavid du Colombier r->rcvseq = 0; 8247dd7cddfSDavid du Colombier r->acksent = 0; 8257dd7cddfSDavid du Colombier r->xmits = 0; 8267dd7cddfSDavid du Colombier r->timeout = 0; 8277dd7cddfSDavid du Colombier r->ref = 0; 8287dd7cddfSDavid du Colombier incref(r); /* one reference for being in the list */ 8297dd7cddfSDavid du Colombier 8307dd7cddfSDavid du Colombier *l = r; 8317dd7cddfSDavid du Colombier } 8327dd7cddfSDavid du Colombier 8337dd7cddfSDavid du Colombier incref(r); 8347dd7cddfSDavid du Colombier return r; 8357dd7cddfSDavid du Colombier } 8367dd7cddfSDavid du Colombier 8377dd7cddfSDavid du Colombier void 8387dd7cddfSDavid du Colombier relput(Reliable *r) 8397dd7cddfSDavid du Colombier { 8407dd7cddfSDavid du Colombier if(decref(r) == 0) 8417dd7cddfSDavid du Colombier free(r); 8427dd7cddfSDavid du Colombier } 8437dd7cddfSDavid du Colombier 8447dd7cddfSDavid du Colombier /* 8457dd7cddfSDavid du Colombier * forget a Reliable state 8467dd7cddfSDavid du Colombier */ 8477dd7cddfSDavid du Colombier void 8487dd7cddfSDavid du Colombier relforget(Conv *c, uchar *ip, int port, int originator) 8497dd7cddfSDavid du Colombier { 8507dd7cddfSDavid du Colombier Rudpcb *ucb; 8517dd7cddfSDavid du Colombier Reliable *r, **l; 8527dd7cddfSDavid du Colombier 8537dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 8547dd7cddfSDavid du Colombier 8557dd7cddfSDavid du Colombier l = &ucb->r; 8567dd7cddfSDavid du Colombier for(r = *l; r; r = *l){ 8577dd7cddfSDavid du Colombier if(ipcmp(ip, r->addr) == 0 && port == r->port){ 8587dd7cddfSDavid du Colombier *l = r->next; 8597dd7cddfSDavid du Colombier if(originator) 8607dd7cddfSDavid du Colombier relsendack(c, r, 1); 8617dd7cddfSDavid du Colombier relhangup(c, r); 8627dd7cddfSDavid du Colombier relput(r); /* remove from the list */ 8637dd7cddfSDavid du Colombier break; 8647dd7cddfSDavid du Colombier } 8657dd7cddfSDavid du Colombier l = &r->next; 8667dd7cddfSDavid du Colombier } 8677dd7cddfSDavid du Colombier } 8687dd7cddfSDavid du Colombier 8697dd7cddfSDavid du Colombier /* 8707dd7cddfSDavid du Colombier * process a rcvd reliable packet. return -1 if not to be passed to user process, 8717dd7cddfSDavid du Colombier * 0 therwise. 8727dd7cddfSDavid du Colombier * 8737dd7cddfSDavid du Colombier * called with ucb locked. 8747dd7cddfSDavid du Colombier */ 8757dd7cddfSDavid du Colombier int 8767dd7cddfSDavid du Colombier reliput(Conv *c, Block *bp, uchar *addr, ushort port) 8777dd7cddfSDavid du Colombier { 8787dd7cddfSDavid du Colombier Block *nbp; 8797dd7cddfSDavid du Colombier Rudpcb *ucb; 8807dd7cddfSDavid du Colombier Rudppriv *upriv; 8817dd7cddfSDavid du Colombier Udphdr *uh; 8827dd7cddfSDavid du Colombier Reliable *r; 8837dd7cddfSDavid du Colombier Rudphdr *rh; 8847dd7cddfSDavid du Colombier ulong seq, ack, sgen, agen, ackreal; 8857dd7cddfSDavid du Colombier int rv = -1; 8867dd7cddfSDavid du Colombier 8877dd7cddfSDavid du Colombier /* get fields */ 8887dd7cddfSDavid du Colombier uh = (Udphdr*)(bp->rp); 8897dd7cddfSDavid du Colombier rh = (Rudphdr*)uh; 8907dd7cddfSDavid du Colombier seq = nhgetl(rh->relseq); 8917dd7cddfSDavid du Colombier sgen = nhgetl(rh->relsgen); 8927dd7cddfSDavid du Colombier ack = nhgetl(rh->relack); 8937dd7cddfSDavid du Colombier agen = nhgetl(rh->relagen); 8947dd7cddfSDavid du Colombier 8957dd7cddfSDavid du Colombier upriv = c->p->priv; 8967dd7cddfSDavid du Colombier ucb = (Rudpcb*)c->ptcl; 8977dd7cddfSDavid du Colombier r = relstate(ucb, addr, port, "input"); 8987dd7cddfSDavid du Colombier 8997dd7cddfSDavid du Colombier DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n", 9007dd7cddfSDavid du Colombier seq, sgen, ack, agen, r->sndgen); 9017dd7cddfSDavid du Colombier 9027dd7cddfSDavid du Colombier /* if acking an incorrect generation, ignore */ 9037dd7cddfSDavid du Colombier if(ack && agen != r->sndgen) 9047dd7cddfSDavid du Colombier goto out; 9057dd7cddfSDavid du Colombier 9067dd7cddfSDavid du Colombier /* Look for a hangup */ 9077dd7cddfSDavid du Colombier if(sgen == Hangupgen) { 9087dd7cddfSDavid du Colombier if(agen == r->sndgen) 9097dd7cddfSDavid du Colombier relforget(c, addr, port, 0); 9107dd7cddfSDavid du Colombier goto out; 9117dd7cddfSDavid du Colombier } 9127dd7cddfSDavid du Colombier 9137dd7cddfSDavid du Colombier /* make sure we're not talking to a new remote side */ 9147dd7cddfSDavid du Colombier if(r->rcvgen != sgen){ 9157dd7cddfSDavid du Colombier if(seq != 0 && seq != 1) 9167dd7cddfSDavid du Colombier goto out; 9177dd7cddfSDavid du Colombier 9187dd7cddfSDavid du Colombier /* new connection */ 9197dd7cddfSDavid du Colombier if(r->rcvgen != 0){ 9207dd7cddfSDavid du Colombier DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen); 9217dd7cddfSDavid du Colombier relhangup(c, r); 9227dd7cddfSDavid du Colombier } 9237dd7cddfSDavid du Colombier r->rcvgen = sgen; 9247dd7cddfSDavid du Colombier } 9257dd7cddfSDavid du Colombier 9267dd7cddfSDavid du Colombier /* dequeue acked packets */ 9277dd7cddfSDavid du Colombier if(ack && agen == r->sndgen){ 9287dd7cddfSDavid du Colombier ackreal = 0; 9297dd7cddfSDavid du Colombier while(r->unacked != nil && INSEQ(ack, r->ackrcvd, r->sndseq)){ 9307dd7cddfSDavid du Colombier nbp = r->unacked; 9317dd7cddfSDavid du Colombier r->unacked = nbp->list; 9327dd7cddfSDavid du Colombier DPRINT("%lud/%lud acked, r->sndgen = %lud\n", 9337dd7cddfSDavid du Colombier ack, agen, r->sndgen); 9347dd7cddfSDavid du Colombier freeb(nbp); 9357dd7cddfSDavid du Colombier r->ackrcvd = NEXTSEQ(r->ackrcvd); 9367dd7cddfSDavid du Colombier ackreal = 1; 9377dd7cddfSDavid du Colombier } 9387dd7cddfSDavid du Colombier 9397dd7cddfSDavid du Colombier /* flow control */ 9407dd7cddfSDavid du Colombier if(UNACKED(r) < Maxunacked/8 && r->blocked) 9417dd7cddfSDavid du Colombier wakeup(&r->vous); 9427dd7cddfSDavid du Colombier 9437dd7cddfSDavid du Colombier /* 9447dd7cddfSDavid du Colombier * retransmit next packet if the acked packet 9457dd7cddfSDavid du Colombier * was transmitted more than once 9467dd7cddfSDavid du Colombier */ 9477dd7cddfSDavid du Colombier if(ackreal && r->unacked != nil){ 9487dd7cddfSDavid du Colombier r->timeout = 0; 9497dd7cddfSDavid du Colombier if(r->xmits > 1){ 9507dd7cddfSDavid du Colombier r->xmits = 1; 9517dd7cddfSDavid du Colombier relrexmit(c, r); 9527dd7cddfSDavid du Colombier } 9537dd7cddfSDavid du Colombier } 9547dd7cddfSDavid du Colombier 9557dd7cddfSDavid du Colombier } 9567dd7cddfSDavid du Colombier 9577dd7cddfSDavid du Colombier /* no message or input queue full */ 9587dd7cddfSDavid du Colombier if(seq == 0 || qfull(c->rq)) 9597dd7cddfSDavid du Colombier goto out; 9607dd7cddfSDavid du Colombier 9617dd7cddfSDavid du Colombier /* refuse out of order delivery */ 9627dd7cddfSDavid du Colombier if(seq != NEXTSEQ(r->rcvseq)){ 9637dd7cddfSDavid du Colombier relsendack(c, r, 0); /* tell him we got it already */ 9647dd7cddfSDavid du Colombier upriv->orders++; 9657dd7cddfSDavid du Colombier DPRINT("out of sequence %lud not %lud\n", seq, NEXTSEQ(r->rcvseq)); 9667dd7cddfSDavid du Colombier goto out; 9677dd7cddfSDavid du Colombier } 9687dd7cddfSDavid du Colombier r->rcvseq = seq; 9697dd7cddfSDavid du Colombier 9707dd7cddfSDavid du Colombier rv = 0; 9717dd7cddfSDavid du Colombier out: 9727dd7cddfSDavid du Colombier relput(r); 9737dd7cddfSDavid du Colombier return rv; 9747dd7cddfSDavid du Colombier } 9757dd7cddfSDavid du Colombier 9767dd7cddfSDavid du Colombier void 9777dd7cddfSDavid du Colombier relsendack(Conv *c, Reliable *r, int hangup) 9787dd7cddfSDavid du Colombier { 9797dd7cddfSDavid du Colombier Udphdr *uh; 9807dd7cddfSDavid du Colombier Block *bp; 9817dd7cddfSDavid du Colombier Rudphdr *rh; 9827dd7cddfSDavid du Colombier int ptcllen; 9837dd7cddfSDavid du Colombier Fs *f; 9847dd7cddfSDavid du Colombier 9857dd7cddfSDavid du Colombier bp = allocb(UDP_IPHDR + UDP_RHDRSIZE); 9867dd7cddfSDavid du Colombier if(bp == nil) 9877dd7cddfSDavid du Colombier return; 9887dd7cddfSDavid du Colombier bp->wp += UDP_IPHDR + UDP_RHDRSIZE; 9897dd7cddfSDavid du Colombier f = c->p->f; 9907dd7cddfSDavid du Colombier uh = (Udphdr *)(bp->rp); 9913ff48bf5SDavid du Colombier uh->vihl = IP_VER4; 9927dd7cddfSDavid du Colombier rh = (Rudphdr*)uh; 9937dd7cddfSDavid du Colombier 9947dd7cddfSDavid du Colombier ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE); 9957dd7cddfSDavid du Colombier uh->Unused = 0; 9967dd7cddfSDavid du Colombier uh->udpproto = IP_UDPPROTO; 9977dd7cddfSDavid du Colombier uh->frag[0] = 0; 9987dd7cddfSDavid du Colombier uh->frag[1] = 0; 9997dd7cddfSDavid du Colombier hnputs(uh->udpplen, ptcllen); 10007dd7cddfSDavid du Colombier 10017dd7cddfSDavid du Colombier v6tov4(uh->udpdst, r->addr); 10027dd7cddfSDavid du Colombier hnputs(uh->udpdport, r->port); 10037dd7cddfSDavid du Colombier hnputs(uh->udpsport, c->lport); 10047dd7cddfSDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0) 10057dd7cddfSDavid du Colombier findlocalip(f, c->laddr, c->raddr); 10067dd7cddfSDavid du Colombier v6tov4(uh->udpsrc, c->laddr); 10077dd7cddfSDavid du Colombier hnputs(uh->udplen, ptcllen); 10087dd7cddfSDavid du Colombier 10097dd7cddfSDavid du Colombier if(hangup) 10107dd7cddfSDavid du Colombier hnputl(rh->relsgen, Hangupgen); 10117dd7cddfSDavid du Colombier else 10127dd7cddfSDavid du Colombier hnputl(rh->relsgen, r->sndgen); 10137dd7cddfSDavid du Colombier hnputl(rh->relseq, 0); 10147dd7cddfSDavid du Colombier hnputl(rh->relagen, r->rcvgen); 10157dd7cddfSDavid du Colombier hnputl(rh->relack, r->rcvseq); 10167dd7cddfSDavid du Colombier 10177dd7cddfSDavid du Colombier if(r->acksent < r->rcvseq) 10187dd7cddfSDavid du Colombier r->acksent = r->rcvseq; 10197dd7cddfSDavid du Colombier 10207dd7cddfSDavid du Colombier uh->udpcksum[0] = 0; 10217dd7cddfSDavid du Colombier uh->udpcksum[1] = 0; 10227dd7cddfSDavid du Colombier hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE)); 10237dd7cddfSDavid du Colombier 10247dd7cddfSDavid du Colombier DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen); 10257dd7cddfSDavid du Colombier doipoput(c, f, bp, 0, c->ttl, c->tos); 10267dd7cddfSDavid du Colombier } 10277dd7cddfSDavid du Colombier 10287dd7cddfSDavid du Colombier 10297dd7cddfSDavid du Colombier /* 10307dd7cddfSDavid du Colombier * called with ucb locked (and c locked if user initiated close) 10317dd7cddfSDavid du Colombier */ 10327dd7cddfSDavid du Colombier void 10337dd7cddfSDavid du Colombier relhangup(Conv *c, Reliable *r) 10347dd7cddfSDavid du Colombier { 10357dd7cddfSDavid du Colombier int n; 10367dd7cddfSDavid du Colombier Block *bp; 10379a747e4fSDavid du Colombier char hup[ERRMAX]; 10387dd7cddfSDavid du Colombier 10397dd7cddfSDavid du Colombier n = snprint(hup, sizeof(hup), "hangup %I!%d", r->addr, r->port); 10407dd7cddfSDavid du Colombier qproduce(c->eq, hup, n); 10417dd7cddfSDavid du Colombier 10427dd7cddfSDavid du Colombier /* 10437dd7cddfSDavid du Colombier * dump any unacked outgoing messages 10447dd7cddfSDavid du Colombier */ 10457dd7cddfSDavid du Colombier for(bp = r->unacked; bp != nil; bp = r->unacked){ 10467dd7cddfSDavid du Colombier r->unacked = bp->list; 10477dd7cddfSDavid du Colombier bp->list = nil; 10487dd7cddfSDavid du Colombier freeb(bp); 10497dd7cddfSDavid du Colombier } 10507dd7cddfSDavid du Colombier 10517dd7cddfSDavid du Colombier r->rcvgen = 0; 10527dd7cddfSDavid du Colombier r->rcvseq = 0; 10537dd7cddfSDavid du Colombier r->acksent = 0; 10547dd7cddfSDavid du Colombier if(generation == Hangupgen) 10557dd7cddfSDavid du Colombier generation++; 10567dd7cddfSDavid du Colombier r->sndgen = generation++; 10577dd7cddfSDavid du Colombier r->sndseq = 0; 10587dd7cddfSDavid du Colombier r->ackrcvd = 0; 10597dd7cddfSDavid du Colombier r->xmits = 0; 10607dd7cddfSDavid du Colombier r->timeout = 0; 10617dd7cddfSDavid du Colombier wakeup(&r->vous); 10627dd7cddfSDavid du Colombier } 10637dd7cddfSDavid du Colombier 10647dd7cddfSDavid du Colombier /* 10657dd7cddfSDavid du Colombier * called with ucb locked 10667dd7cddfSDavid du Colombier */ 10677dd7cddfSDavid du Colombier void 10687dd7cddfSDavid du Colombier relrexmit(Conv *c, Reliable *r) 10697dd7cddfSDavid du Colombier { 10707dd7cddfSDavid du Colombier Rudppriv *upriv; 10717dd7cddfSDavid du Colombier Block *np; 10727dd7cddfSDavid du Colombier Fs *f; 10737dd7cddfSDavid du Colombier 10747dd7cddfSDavid du Colombier upriv = c->p->priv; 10757dd7cddfSDavid du Colombier f = c->p->f; 10767dd7cddfSDavid du Colombier r->timeout = 0; 10777dd7cddfSDavid du Colombier if(r->xmits++ > Rudpmaxxmit){ 10787dd7cddfSDavid du Colombier relhangup(c, r); 10797dd7cddfSDavid du Colombier return; 10807dd7cddfSDavid du Colombier } 10817dd7cddfSDavid du Colombier 10827dd7cddfSDavid du Colombier upriv->rxmits++; 10837dd7cddfSDavid du Colombier np = copyblock(r->unacked, blocklen(r->unacked)); 10847dd7cddfSDavid du Colombier DPRINT("rxmit r->ackrvcd+1 = %lud\n", r->ackrcvd+1); 10857dd7cddfSDavid du Colombier doipoput(c, f, np, 0, c->ttl, c->tos); 10867dd7cddfSDavid du Colombier } 1087