17dd7cddfSDavid du Colombier #include "u.h" 27dd7cddfSDavid du Colombier #include "../port/lib.h" 37dd7cddfSDavid du Colombier #include "mem.h" 47dd7cddfSDavid du Colombier #include "dat.h" 57dd7cddfSDavid du Colombier #include "fns.h" 67dd7cddfSDavid du Colombier #include "../port/error.h" 77dd7cddfSDavid du Colombier 87dd7cddfSDavid du Colombier #include "ip.h" 93ff48bf5SDavid du Colombier #include "ipv6.h" 103ff48bf5SDavid du Colombier 117dd7cddfSDavid du Colombier 127dd7cddfSDavid du Colombier #define DPRINT if(0)print 137dd7cddfSDavid du Colombier 147dd7cddfSDavid du Colombier enum 157dd7cddfSDavid du Colombier { 163ff48bf5SDavid du Colombier UDP_UDPHDR_SZ = 8, 173ff48bf5SDavid du Colombier 183ff48bf5SDavid du Colombier UDP4_PHDR_OFF = 8, 193ff48bf5SDavid du Colombier UDP4_PHDR_SZ = 12, 203ff48bf5SDavid du Colombier UDP4_IPHDR_SZ = 20, 213ff48bf5SDavid du Colombier UDP6_IPHDR_SZ = 40, 223ff48bf5SDavid du Colombier UDP6_PHDR_SZ = 40, 233ff48bf5SDavid du Colombier UDP6_PHDR_OFF = 0, 243ff48bf5SDavid du Colombier 257dd7cddfSDavid du Colombier IP_UDPPROTO = 17, 267dd7cddfSDavid du Colombier UDP_USEAD6 = 36, 277dd7cddfSDavid du Colombier UDP_USEAD4 = 12, 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier Udprxms = 200, 307dd7cddfSDavid du Colombier Udptickms = 100, 317dd7cddfSDavid du Colombier Udpmaxxmit = 10, 327dd7cddfSDavid du Colombier }; 337dd7cddfSDavid du Colombier 343ff48bf5SDavid du Colombier typedef struct Udp4hdr Udp4hdr; 353ff48bf5SDavid du Colombier struct Udp4hdr 367dd7cddfSDavid du Colombier { 377dd7cddfSDavid du Colombier /* ip header */ 387dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */ 397dd7cddfSDavid du Colombier uchar tos; /* Type of service */ 407dd7cddfSDavid du Colombier uchar length[2]; /* packet length */ 417dd7cddfSDavid du Colombier uchar id[2]; /* Identification */ 427dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */ 437dd7cddfSDavid du Colombier uchar Unused; 447dd7cddfSDavid du Colombier uchar udpproto; /* Protocol */ 457dd7cddfSDavid du Colombier uchar udpplen[2]; /* Header plus data length */ 463ff48bf5SDavid du Colombier uchar udpsrc[IPv4addrlen]; /* Ip source */ 473ff48bf5SDavid du Colombier uchar udpdst[IPv4addrlen]; /* Ip destination */ 483ff48bf5SDavid du Colombier 493ff48bf5SDavid du Colombier /* udp header */ 503ff48bf5SDavid du Colombier uchar udpsport[2]; /* Source port */ 513ff48bf5SDavid du Colombier uchar udpdport[2]; /* Destination port */ 523ff48bf5SDavid du Colombier uchar udplen[2]; /* data length */ 533ff48bf5SDavid du Colombier uchar udpcksum[2]; /* Checksum */ 543ff48bf5SDavid du Colombier }; 553ff48bf5SDavid du Colombier 563ff48bf5SDavid du Colombier typedef struct Udp6hdr Udp6hdr; 573ff48bf5SDavid du Colombier struct Udp6hdr { 583ff48bf5SDavid du Colombier uchar viclfl[4]; 593ff48bf5SDavid du Colombier uchar len[2]; 603ff48bf5SDavid du Colombier uchar nextheader; 613ff48bf5SDavid du Colombier uchar hoplimit; 623ff48bf5SDavid du Colombier uchar udpsrc[IPaddrlen]; 633ff48bf5SDavid du Colombier uchar udpdst[IPaddrlen]; 647dd7cddfSDavid du Colombier 657dd7cddfSDavid du Colombier /* udp header */ 667dd7cddfSDavid du Colombier uchar udpsport[2]; /* Source port */ 677dd7cddfSDavid du Colombier uchar udpdport[2]; /* Destination port */ 687dd7cddfSDavid du Colombier uchar udplen[2]; /* data length */ 697dd7cddfSDavid du Colombier uchar udpcksum[2]; /* Checksum */ 707dd7cddfSDavid du Colombier }; 717dd7cddfSDavid du Colombier 7259cc4ca5SDavid du Colombier /* MIB II counters */ 7380ee5cbfSDavid du Colombier typedef struct Udpstats Udpstats; 7480ee5cbfSDavid du Colombier struct Udpstats 7580ee5cbfSDavid du Colombier { 7680ee5cbfSDavid du Colombier ulong udpInDatagrams; 7780ee5cbfSDavid du Colombier ulong udpNoPorts; 7880ee5cbfSDavid du Colombier ulong udpInErrors; 7980ee5cbfSDavid du Colombier ulong udpOutDatagrams; 807dd7cddfSDavid du Colombier }; 817dd7cddfSDavid du Colombier 827dd7cddfSDavid du Colombier typedef struct Udppriv Udppriv; 837dd7cddfSDavid du Colombier struct Udppriv 847dd7cddfSDavid du Colombier { 8580ee5cbfSDavid du Colombier Ipht ht; 8680ee5cbfSDavid du Colombier 8780ee5cbfSDavid du Colombier /* MIB counters */ 8880ee5cbfSDavid du Colombier Udpstats ustats; 8980ee5cbfSDavid du Colombier 9080ee5cbfSDavid du Colombier /* non-MIB stats */ 9180ee5cbfSDavid du Colombier ulong csumerr; /* checksum errors */ 9280ee5cbfSDavid du Colombier ulong lenerr; /* short packet */ 937dd7cddfSDavid du Colombier }; 947dd7cddfSDavid du Colombier 953ff48bf5SDavid du Colombier void (*etherprofiler)(char *name, int qlen); 96*e6c6b7f8SDavid du Colombier void udpkick(void *x, Block *bp); 973ff48bf5SDavid du Colombier 987dd7cddfSDavid du Colombier /* 997dd7cddfSDavid du Colombier * protocol specific part of Conv 1007dd7cddfSDavid du Colombier */ 1017dd7cddfSDavid du Colombier typedef struct Udpcb Udpcb; 1027dd7cddfSDavid du Colombier struct Udpcb 1037dd7cddfSDavid du Colombier { 1047dd7cddfSDavid du Colombier QLock; 1057dd7cddfSDavid du Colombier uchar headers; 1067dd7cddfSDavid du Colombier }; 1077dd7cddfSDavid du Colombier 1087dd7cddfSDavid du Colombier static char* 1097dd7cddfSDavid du Colombier udpconnect(Conv *c, char **argv, int argc) 1107dd7cddfSDavid du Colombier { 1117dd7cddfSDavid du Colombier char *e; 11280ee5cbfSDavid du Colombier Udppriv *upriv; 1137dd7cddfSDavid du Colombier 11480ee5cbfSDavid du Colombier upriv = c->p->priv; 1157dd7cddfSDavid du Colombier e = Fsstdconnect(c, argv, argc); 1167dd7cddfSDavid du Colombier Fsconnected(c, e); 1173ff48bf5SDavid du Colombier if(e != nil) 1187dd7cddfSDavid du Colombier return e; 1193ff48bf5SDavid du Colombier 1203ff48bf5SDavid du Colombier iphtadd(&upriv->ht, c); 1213ff48bf5SDavid du Colombier return nil; 1227dd7cddfSDavid du Colombier } 1237dd7cddfSDavid du Colombier 1247dd7cddfSDavid du Colombier 1257dd7cddfSDavid du Colombier static int 1267dd7cddfSDavid du Colombier udpstate(Conv *c, char *state, int n) 1277dd7cddfSDavid du Colombier { 1287dd7cddfSDavid du Colombier return snprint(state, n, "%s", c->inuse?"Open":"Closed"); 1297dd7cddfSDavid du Colombier } 1307dd7cddfSDavid du Colombier 1317dd7cddfSDavid du Colombier static char* 1327dd7cddfSDavid du Colombier udpannounce(Conv *c, char** argv, int argc) 1337dd7cddfSDavid du Colombier { 1347dd7cddfSDavid du Colombier char *e; 13580ee5cbfSDavid du Colombier Udppriv *upriv; 1367dd7cddfSDavid du Colombier 13780ee5cbfSDavid du Colombier upriv = c->p->priv; 1387dd7cddfSDavid du Colombier e = Fsstdannounce(c, argv, argc); 1397dd7cddfSDavid du Colombier if(e != nil) 1407dd7cddfSDavid du Colombier return e; 1417dd7cddfSDavid du Colombier Fsconnected(c, nil); 14280ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c); 1437dd7cddfSDavid du Colombier 1447dd7cddfSDavid du Colombier return nil; 1457dd7cddfSDavid du Colombier } 1467dd7cddfSDavid du Colombier 1477dd7cddfSDavid du Colombier static void 1487dd7cddfSDavid du Colombier udpcreate(Conv *c) 1497dd7cddfSDavid du Colombier { 1503ff48bf5SDavid du Colombier c->rq = qopen(128*1024, Qmsg, 0, 0); 151*e6c6b7f8SDavid du Colombier c->wq = qbypass(udpkick, c); 1527dd7cddfSDavid du Colombier } 1537dd7cddfSDavid du Colombier 1547dd7cddfSDavid du Colombier static void 1557dd7cddfSDavid du Colombier udpclose(Conv *c) 1567dd7cddfSDavid du Colombier { 1577dd7cddfSDavid du Colombier Udpcb *ucb; 15880ee5cbfSDavid du Colombier Udppriv *upriv; 15980ee5cbfSDavid du Colombier 16080ee5cbfSDavid du Colombier upriv = c->p->priv; 16180ee5cbfSDavid du Colombier iphtrem(&upriv->ht, c); 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier c->state = 0; 1647dd7cddfSDavid du Colombier qclose(c->rq); 1657dd7cddfSDavid du Colombier qclose(c->wq); 1667dd7cddfSDavid du Colombier qclose(c->eq); 1677dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 1687dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr); 1697dd7cddfSDavid du Colombier c->lport = 0; 1707dd7cddfSDavid du Colombier c->rport = 0; 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl; 1737dd7cddfSDavid du Colombier ucb->headers = 0; 1743ff48bf5SDavid du Colombier 1753ff48bf5SDavid du Colombier qunlock(c); 1767dd7cddfSDavid du Colombier } 1777dd7cddfSDavid du Colombier 1787dd7cddfSDavid du Colombier void 179*e6c6b7f8SDavid du Colombier udpkick(void *x, Block *bp) 1807dd7cddfSDavid du Colombier { 1813ff48bf5SDavid du Colombier Conv *c = x; 1823ff48bf5SDavid du Colombier Udp4hdr *uh4; 1833ff48bf5SDavid du Colombier Udp6hdr *uh6; 1847dd7cddfSDavid du Colombier ushort rport; 1857dd7cddfSDavid du Colombier uchar laddr[IPaddrlen], raddr[IPaddrlen]; 1867dd7cddfSDavid du Colombier Udpcb *ucb; 1877dd7cddfSDavid du Colombier int dlen, ptcllen; 1887dd7cddfSDavid du Colombier Udppriv *upriv; 1897dd7cddfSDavid du Colombier Fs *f; 1903ff48bf5SDavid du Colombier int version; 1917dd7cddfSDavid du Colombier 1927dd7cddfSDavid du Colombier upriv = c->p->priv; 1937dd7cddfSDavid du Colombier f = c->p->f; 1947dd7cddfSDavid du Colombier 1957dd7cddfSDavid du Colombier netlog(c->p->f, Logudp, "udp: kick\n"); 1967dd7cddfSDavid du Colombier if(bp == nil) 1977dd7cddfSDavid du Colombier return; 1987dd7cddfSDavid du Colombier 1997dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl; 2007dd7cddfSDavid du Colombier switch(ucb->headers) { 2017dd7cddfSDavid du Colombier case 6: 2027dd7cddfSDavid du Colombier /* get user specified addresses */ 2037dd7cddfSDavid du Colombier bp = pullupblock(bp, UDP_USEAD6); 2047dd7cddfSDavid du Colombier if(bp == nil) 2057dd7cddfSDavid du Colombier return; 2067dd7cddfSDavid du Colombier ipmove(raddr, bp->rp); 2077dd7cddfSDavid du Colombier bp->rp += IPaddrlen; 2087dd7cddfSDavid du Colombier ipmove(laddr, bp->rp); 2097dd7cddfSDavid du Colombier bp->rp += IPaddrlen; 2107dd7cddfSDavid du Colombier /* pick interface closest to dest */ 2117dd7cddfSDavid du Colombier if(ipforme(f, laddr) != Runi) 2127dd7cddfSDavid du Colombier findlocalip(f, laddr, raddr); 2137dd7cddfSDavid du Colombier rport = nhgets(bp->rp); 2143ff48bf5SDavid du Colombier bp->rp += 2+2; /* Ignore local port */ 2157dd7cddfSDavid du Colombier break; 2167dd7cddfSDavid du Colombier case 4: 2177dd7cddfSDavid du Colombier bp = pullupblock(bp, UDP_USEAD4); 2187dd7cddfSDavid du Colombier if(bp == nil) 2197dd7cddfSDavid du Colombier return; 2207dd7cddfSDavid du Colombier v4tov6(raddr, bp->rp); 2217dd7cddfSDavid du Colombier bp->rp += IPv4addrlen; 2227dd7cddfSDavid du Colombier v4tov6(laddr, bp->rp); 2237dd7cddfSDavid du Colombier bp->rp += IPv4addrlen; 2247dd7cddfSDavid du Colombier if(ipforme(f, laddr) != Runi) 2257dd7cddfSDavid du Colombier findlocalip(f, laddr, raddr); 2267dd7cddfSDavid du Colombier rport = nhgets(bp->rp); 2277dd7cddfSDavid du Colombier bp->rp += 2+2; 2287dd7cddfSDavid du Colombier break; 2297dd7cddfSDavid du Colombier default: 2307dd7cddfSDavid du Colombier rport = 0; 2317dd7cddfSDavid du Colombier break; 2327dd7cddfSDavid du Colombier } 2337dd7cddfSDavid du Colombier 2343ff48bf5SDavid du Colombier if(ucb->headers == 6) { 2353ff48bf5SDavid du Colombier if(memcmp(laddr, v4prefix, IPv4off) == 0 || 2363ff48bf5SDavid du Colombier ipcmp(laddr, IPnoaddr) == 0) 2373ff48bf5SDavid du Colombier version = 4; 2383ff48bf5SDavid du Colombier else 2393ff48bf5SDavid du Colombier version = 6; 2403ff48bf5SDavid du Colombier } 2413ff48bf5SDavid du Colombier else if(ucb->headers == 4) 2423ff48bf5SDavid du Colombier version = 4; 2433ff48bf5SDavid du Colombier else { 2443ff48bf5SDavid du Colombier if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 && 2453ff48bf5SDavid du Colombier memcmp(c->laddr, v4prefix, IPv4off) == 0) 2463ff48bf5SDavid du Colombier || ipcmp(c->raddr, IPnoaddr) == 0) 2473ff48bf5SDavid du Colombier version = 4; 2483ff48bf5SDavid du Colombier else 2493ff48bf5SDavid du Colombier version = 6; 2503ff48bf5SDavid du Colombier } 2513ff48bf5SDavid du Colombier 2527dd7cddfSDavid du Colombier dlen = blocklen(bp); 2537dd7cddfSDavid du Colombier 2543ff48bf5SDavid du Colombier /* fill in pseudo header and compute checksum */ 2553ff48bf5SDavid du Colombier switch(version){ 2563ff48bf5SDavid du Colombier case V4: 2573ff48bf5SDavid du Colombier bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ); 2587dd7cddfSDavid du Colombier if(bp == nil) 2597dd7cddfSDavid du Colombier return; 2607dd7cddfSDavid du Colombier 2613ff48bf5SDavid du Colombier uh4 = (Udp4hdr *)(bp->rp); 2623ff48bf5SDavid du Colombier ptcllen = dlen + UDP_UDPHDR_SZ; 2633ff48bf5SDavid du Colombier uh4->Unused = 0; 2643ff48bf5SDavid du Colombier uh4->udpproto = IP_UDPPROTO; 2653ff48bf5SDavid du Colombier uh4->frag[0] = 0; 2663ff48bf5SDavid du Colombier uh4->frag[1] = 0; 2673ff48bf5SDavid du Colombier hnputs(uh4->udpplen, ptcllen); 2683ff48bf5SDavid du Colombier if(ucb->headers == 4 || ucb->headers == 6) { 2693ff48bf5SDavid du Colombier v6tov4(uh4->udpdst, raddr); 2703ff48bf5SDavid du Colombier hnputs(uh4->udpdport, rport); 2713ff48bf5SDavid du Colombier v6tov4(uh4->udpsrc, laddr); 2723ff48bf5SDavid du Colombier } else { 2733ff48bf5SDavid du Colombier v6tov4(uh4->udpdst, c->raddr); 2743ff48bf5SDavid du Colombier hnputs(uh4->udpdport, c->rport); 2757dd7cddfSDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0) 2767dd7cddfSDavid du Colombier findlocalip(f, c->laddr, c->raddr); 2773ff48bf5SDavid du Colombier v6tov4(uh4->udpsrc, c->laddr); 2783ff48bf5SDavid du Colombier } 2793ff48bf5SDavid du Colombier hnputs(uh4->udpsport, c->lport); 2803ff48bf5SDavid du Colombier hnputs(uh4->udplen, ptcllen); 2813ff48bf5SDavid du Colombier uh4->udpcksum[0] = 0; 2823ff48bf5SDavid du Colombier uh4->udpcksum[1] = 0; 2833ff48bf5SDavid du Colombier hnputs(uh4->udpcksum, 2843ff48bf5SDavid du Colombier ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ)); 2853ff48bf5SDavid du Colombier uh4->vihl = IP_VER4; 2863ff48bf5SDavid du Colombier ipoput4(f, bp, 0, c->ttl, c->tos); 2877dd7cddfSDavid du Colombier break; 2883ff48bf5SDavid du Colombier 2893ff48bf5SDavid du Colombier case V6: 2903ff48bf5SDavid du Colombier bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ); 2913ff48bf5SDavid du Colombier if(bp == nil) 2923ff48bf5SDavid du Colombier return; 2933ff48bf5SDavid du Colombier 2943ff48bf5SDavid du Colombier // using the v6 ip header to create pseudo header 2953ff48bf5SDavid du Colombier // first then reset it to the normal ip header 2963ff48bf5SDavid du Colombier uh6 = (Udp6hdr *)(bp->rp); 2973ff48bf5SDavid du Colombier memset(uh6, 0, 8); 2983ff48bf5SDavid du Colombier ptcllen = dlen + UDP_UDPHDR_SZ; 2993ff48bf5SDavid du Colombier hnputl(uh6->viclfl, ptcllen); 3003ff48bf5SDavid du Colombier uh6->hoplimit = IP_UDPPROTO; 3013ff48bf5SDavid du Colombier if(ucb->headers == 6) { 3023ff48bf5SDavid du Colombier ipmove(uh6->udpdst, raddr); 3033ff48bf5SDavid du Colombier hnputs(uh6->udpdport, rport); 3043ff48bf5SDavid du Colombier ipmove(uh6->udpsrc, laddr); 3053ff48bf5SDavid du Colombier } else { 3063ff48bf5SDavid du Colombier ipmove(uh6->udpdst, c->raddr); 3073ff48bf5SDavid du Colombier hnputs(uh6->udpdport, c->rport); 3083ff48bf5SDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0) 3093ff48bf5SDavid du Colombier findlocalip(f, c->laddr, c->raddr); 3103ff48bf5SDavid du Colombier ipmove(uh6->udpsrc, c->laddr); 3117dd7cddfSDavid du Colombier } 3123ff48bf5SDavid du Colombier hnputs(uh6->udpsport, c->lport); 3133ff48bf5SDavid du Colombier hnputs(uh6->udplen, ptcllen); 3143ff48bf5SDavid du Colombier uh6->udpcksum[0] = 0; 3153ff48bf5SDavid du Colombier uh6->udpcksum[1] = 0; 3163ff48bf5SDavid du Colombier hnputs(uh6->udpcksum, 3173ff48bf5SDavid du Colombier ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ)); 3183ff48bf5SDavid du Colombier memset(uh6, 0, 8); 3193ff48bf5SDavid du Colombier uh6->viclfl[0] = IP_VER6; 3203ff48bf5SDavid du Colombier hnputs(uh6->len, ptcllen); 3213ff48bf5SDavid du Colombier uh6->nextheader = IP_UDPPROTO; 3223ff48bf5SDavid du Colombier ipoput6(f, bp, 0, c->ttl, c->tos); 3233ff48bf5SDavid du Colombier break; 3247dd7cddfSDavid du Colombier 3253ff48bf5SDavid du Colombier default: 3263ff48bf5SDavid du Colombier panic("udpkick: version %d", version); 3273ff48bf5SDavid du Colombier } 32880ee5cbfSDavid du Colombier upriv->ustats.udpOutDatagrams++; 32980ee5cbfSDavid du Colombier } 33080ee5cbfSDavid du Colombier 3317dd7cddfSDavid du Colombier void 3329a747e4fSDavid du Colombier udpiput(Proto *udp, Ipifc *ifc, Block *bp) 3337dd7cddfSDavid du Colombier { 3343ff48bf5SDavid du Colombier int len; 3353ff48bf5SDavid du Colombier Udp4hdr *uh4; 3363ff48bf5SDavid du Colombier Udp6hdr *uh6; 33780ee5cbfSDavid du Colombier Conv *c; 3387dd7cddfSDavid du Colombier Udpcb *ucb; 3397dd7cddfSDavid du Colombier uchar raddr[IPaddrlen], laddr[IPaddrlen]; 3407dd7cddfSDavid du Colombier ushort rport, lport; 3417dd7cddfSDavid du Colombier Udppriv *upriv; 3427dd7cddfSDavid du Colombier Fs *f; 3433ff48bf5SDavid du Colombier int version; 3443ff48bf5SDavid du Colombier int ottl, oviclfl, olen; 3457dd7cddfSDavid du Colombier 3467dd7cddfSDavid du Colombier upriv = udp->priv; 3477dd7cddfSDavid du Colombier f = udp->f; 34880ee5cbfSDavid du Colombier upriv->ustats.udpInDatagrams++; 3497dd7cddfSDavid du Colombier 3503ff48bf5SDavid du Colombier uh4 = (Udp4hdr*)(bp->rp); 3513ff48bf5SDavid du Colombier version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4; 3527dd7cddfSDavid du Colombier 3533ff48bf5SDavid du Colombier /* Put back pseudo header for checksum 3543ff48bf5SDavid du Colombier * (remember old values for icmpnoconv()) */ 3553ff48bf5SDavid du Colombier switch(version) { 3563ff48bf5SDavid du Colombier case V4: 3573ff48bf5SDavid du Colombier ottl = uh4->Unused; 3583ff48bf5SDavid du Colombier uh4->Unused = 0; 3593ff48bf5SDavid du Colombier len = nhgets(uh4->udplen); 3603ff48bf5SDavid du Colombier olen = nhgets(uh4->udpplen); 3613ff48bf5SDavid du Colombier hnputs(uh4->udpplen, len); 3627dd7cddfSDavid du Colombier 3633ff48bf5SDavid du Colombier v4tov6(raddr, uh4->udpsrc); 3643ff48bf5SDavid du Colombier v4tov6(laddr, uh4->udpdst); 3653ff48bf5SDavid du Colombier lport = nhgets(uh4->udpdport); 3663ff48bf5SDavid du Colombier rport = nhgets(uh4->udpsport); 3677dd7cddfSDavid du Colombier 3683ff48bf5SDavid du Colombier if(nhgets(uh4->udpcksum)) { 3693ff48bf5SDavid du Colombier if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) { 37080ee5cbfSDavid du Colombier upriv->ustats.udpInErrors++; 3717dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: checksum error %I\n", raddr); 3727dd7cddfSDavid du Colombier DPRINT("udp: checksum error %I\n", raddr); 3737dd7cddfSDavid du Colombier freeblist(bp); 3747dd7cddfSDavid du Colombier return; 3757dd7cddfSDavid du Colombier } 3767dd7cddfSDavid du Colombier } 3773ff48bf5SDavid du Colombier uh4->Unused = ottl; 3783ff48bf5SDavid du Colombier hnputs(uh4->udpplen, olen); 3793ff48bf5SDavid du Colombier break; 3803ff48bf5SDavid du Colombier case V6: 3813ff48bf5SDavid du Colombier uh6 = (Udp6hdr*)(bp->rp); 3823ff48bf5SDavid du Colombier len = nhgets(uh6->udplen); 3833ff48bf5SDavid du Colombier oviclfl = nhgetl(uh6->viclfl); 3843ff48bf5SDavid du Colombier olen = nhgets(uh6->len); 3853ff48bf5SDavid du Colombier ottl = uh6->hoplimit; 3863ff48bf5SDavid du Colombier ipmove(raddr, uh6->udpsrc); 3873ff48bf5SDavid du Colombier ipmove(laddr, uh6->udpdst); 3883ff48bf5SDavid du Colombier lport = nhgets(uh6->udpdport); 3893ff48bf5SDavid du Colombier rport = nhgets(uh6->udpsport); 3903ff48bf5SDavid du Colombier memset(uh6, 0, 8); 3913ff48bf5SDavid du Colombier hnputl(uh6->viclfl, len); 3923ff48bf5SDavid du Colombier uh6->hoplimit = IP_UDPPROTO; 3933ff48bf5SDavid du Colombier if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) { 3943ff48bf5SDavid du Colombier upriv->ustats.udpInErrors++; 3953ff48bf5SDavid du Colombier netlog(f, Logudp, "udp: checksum error %I\n", raddr); 3963ff48bf5SDavid du Colombier DPRINT("udp: checksum error %I\n", raddr); 3973ff48bf5SDavid du Colombier freeblist(bp); 3983ff48bf5SDavid du Colombier return; 3993ff48bf5SDavid du Colombier } 4003ff48bf5SDavid du Colombier hnputl(uh6->viclfl, oviclfl); 4013ff48bf5SDavid du Colombier hnputs(uh6->len, olen); 4023ff48bf5SDavid du Colombier uh6->nextheader = IP_UDPPROTO; 4033ff48bf5SDavid du Colombier uh6->hoplimit = ottl; 4043ff48bf5SDavid du Colombier break; 4053ff48bf5SDavid du Colombier default: 4063ff48bf5SDavid du Colombier panic("udpiput: version %d", version); 4073ff48bf5SDavid du Colombier return; /* to avoid a warning */ 4083ff48bf5SDavid du Colombier } 4097dd7cddfSDavid du Colombier 4107dd7cddfSDavid du Colombier qlock(udp); 4117dd7cddfSDavid du Colombier 41280ee5cbfSDavid du Colombier c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); 4137dd7cddfSDavid du Colombier if(c == nil){ 41480ee5cbfSDavid du Colombier /* no converstation found */ 41580ee5cbfSDavid du Colombier upriv->ustats.udpNoPorts++; 4167dd7cddfSDavid du Colombier qunlock(udp); 4177dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, 4187dd7cddfSDavid du Colombier laddr, lport); 4193ff48bf5SDavid du Colombier 4203ff48bf5SDavid du Colombier switch(version){ 4213ff48bf5SDavid du Colombier case V4: 4227dd7cddfSDavid du Colombier icmpnoconv(f, bp); 4233ff48bf5SDavid du Colombier break; 4243ff48bf5SDavid du Colombier case V6: 4253ff48bf5SDavid du Colombier icmphostunr(f, ifc, bp, icmp6_port_unreach, 0); 4263ff48bf5SDavid du Colombier break; 4273ff48bf5SDavid du Colombier default: 4283ff48bf5SDavid du Colombier panic("udpiput2: version %d", version); 4293ff48bf5SDavid du Colombier } 4303ff48bf5SDavid du Colombier 4317dd7cddfSDavid du Colombier freeblist(bp); 4327dd7cddfSDavid du Colombier return; 4337dd7cddfSDavid du Colombier } 43480ee5cbfSDavid du Colombier ucb = (Udpcb*)c->ptcl; 43580ee5cbfSDavid du Colombier 43680ee5cbfSDavid du Colombier if(c->state == Announced){ 43780ee5cbfSDavid du Colombier if(ucb->headers == 0){ 43880ee5cbfSDavid du Colombier /* create a new conversation */ 4393ff48bf5SDavid du Colombier if(ipforme(f, laddr) != Runi) { 4403ff48bf5SDavid du Colombier switch(version){ 4413ff48bf5SDavid du Colombier case V4: 4429a747e4fSDavid du Colombier v4tov6(laddr, ifc->lifc->local); 4433ff48bf5SDavid du Colombier break; 4443ff48bf5SDavid du Colombier case V6: 4453ff48bf5SDavid du Colombier ipmove(laddr, ifc->lifc->local); 4463ff48bf5SDavid du Colombier break; 4473ff48bf5SDavid du Colombier default: 4483ff48bf5SDavid du Colombier panic("udpiput3: version %d", version); 4493ff48bf5SDavid du Colombier } 4503ff48bf5SDavid du Colombier } 4513ff48bf5SDavid du Colombier c = Fsnewcall(c, raddr, rport, laddr, lport, version); 45280ee5cbfSDavid du Colombier if(c == nil){ 45380ee5cbfSDavid du Colombier qunlock(udp); 45480ee5cbfSDavid du Colombier freeblist(bp); 45580ee5cbfSDavid du Colombier return; 45680ee5cbfSDavid du Colombier } 45780ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c); 45880ee5cbfSDavid du Colombier ucb = (Udpcb*)c->ptcl; 45980ee5cbfSDavid du Colombier } 4607dd7cddfSDavid du Colombier } 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier qlock(c); 4637dd7cddfSDavid du Colombier qunlock(udp); 4647dd7cddfSDavid du Colombier 4657dd7cddfSDavid du Colombier /* 4667dd7cddfSDavid du Colombier * Trim the packet down to data size 4677dd7cddfSDavid du Colombier */ 4683ff48bf5SDavid du Colombier len -= UDP_UDPHDR_SZ; 4693ff48bf5SDavid du Colombier switch(version){ 4703ff48bf5SDavid du Colombier case V4: 4713ff48bf5SDavid du Colombier bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len); 4723ff48bf5SDavid du Colombier break; 4733ff48bf5SDavid du Colombier case V6: 4743ff48bf5SDavid du Colombier bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len); 4753ff48bf5SDavid du Colombier break; 4763ff48bf5SDavid du Colombier default: 4773ff48bf5SDavid du Colombier bp = nil; 4783ff48bf5SDavid du Colombier panic("udpiput4: version %d", version); 4793ff48bf5SDavid du Colombier } 4807dd7cddfSDavid du Colombier if(bp == nil){ 4817dd7cddfSDavid du Colombier qunlock(c); 4827dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, 4837dd7cddfSDavid du Colombier laddr, lport); 48480ee5cbfSDavid du Colombier upriv->lenerr++; 4857dd7cddfSDavid du Colombier return; 4867dd7cddfSDavid du Colombier } 4877dd7cddfSDavid du Colombier 4887dd7cddfSDavid du Colombier netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport, 4897dd7cddfSDavid du Colombier laddr, lport, len); 4907dd7cddfSDavid du Colombier 4917dd7cddfSDavid du Colombier switch(ucb->headers){ 4927dd7cddfSDavid du Colombier case 6: 4937dd7cddfSDavid du Colombier /* pass the src address */ 4947dd7cddfSDavid du Colombier bp = padblock(bp, UDP_USEAD6); 4957dd7cddfSDavid du Colombier ipmove(bp->rp, raddr); 4967dd7cddfSDavid du Colombier if(ipforme(f, laddr) == Runi) 4977dd7cddfSDavid du Colombier ipmove(bp->rp+IPaddrlen, laddr); 4987dd7cddfSDavid du Colombier else 4999a747e4fSDavid du Colombier ipmove(bp->rp+IPaddrlen, ifc->lifc->local); 5007dd7cddfSDavid du Colombier hnputs(bp->rp+2*IPaddrlen, rport); 5017dd7cddfSDavid du Colombier hnputs(bp->rp+2*IPaddrlen+2, lport); 5027dd7cddfSDavid du Colombier break; 5037dd7cddfSDavid du Colombier case 4: 5047dd7cddfSDavid du Colombier /* pass the src address */ 5057dd7cddfSDavid du Colombier bp = padblock(bp, UDP_USEAD4); 5067dd7cddfSDavid du Colombier v6tov4(bp->rp, raddr); 5077dd7cddfSDavid du Colombier if(ipforme(f, laddr) == Runi) 5087dd7cddfSDavid du Colombier v6tov4(bp->rp+IPv4addrlen, laddr); 5097dd7cddfSDavid du Colombier else 5109a747e4fSDavid du Colombier v6tov4(bp->rp+IPv4addrlen, ifc->lifc->local); 5117dd7cddfSDavid du Colombier hnputs(bp->rp + 2*IPv4addrlen, rport); 5127dd7cddfSDavid du Colombier hnputs(bp->rp + 2*IPv4addrlen + 2, lport); 5137dd7cddfSDavid du Colombier break; 5147dd7cddfSDavid du Colombier } 5157dd7cddfSDavid du Colombier 5167dd7cddfSDavid du Colombier if(bp->next) 5177dd7cddfSDavid du Colombier bp = concatblock(bp); 5187dd7cddfSDavid du Colombier 5197dd7cddfSDavid du Colombier if(qfull(c->rq)){ 5207dd7cddfSDavid du Colombier qunlock(c); 5217dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, 5227dd7cddfSDavid du Colombier laddr, lport); 5237dd7cddfSDavid du Colombier freeblist(bp); 5247dd7cddfSDavid du Colombier return; 5257dd7cddfSDavid du Colombier } 5267dd7cddfSDavid du Colombier 5277dd7cddfSDavid du Colombier qpass(c->rq, bp); 5287dd7cddfSDavid du Colombier qunlock(c); 5297dd7cddfSDavid du Colombier 5307dd7cddfSDavid du Colombier } 5317dd7cddfSDavid du Colombier 5327dd7cddfSDavid du Colombier char* 5337dd7cddfSDavid du Colombier udpctl(Conv *c, char **f, int n) 5347dd7cddfSDavid du Colombier { 5357dd7cddfSDavid du Colombier Udpcb *ucb; 5367dd7cddfSDavid du Colombier 5377dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl; 5387dd7cddfSDavid du Colombier if(n == 1){ 5397dd7cddfSDavid du Colombier if(strcmp(f[0], "headers4") == 0){ 5407dd7cddfSDavid du Colombier ucb->headers = 4; 5417dd7cddfSDavid du Colombier return nil; 5427dd7cddfSDavid du Colombier } else if(strcmp(f[0], "headers") == 0){ 5437dd7cddfSDavid du Colombier ucb->headers = 6; 5447dd7cddfSDavid du Colombier return nil; 5457dd7cddfSDavid du Colombier } 5467dd7cddfSDavid du Colombier } 5477dd7cddfSDavid du Colombier return "unknown control request"; 5487dd7cddfSDavid du Colombier } 5497dd7cddfSDavid du Colombier 5507dd7cddfSDavid du Colombier void 5517dd7cddfSDavid du Colombier udpadvise(Proto *udp, Block *bp, char *msg) 5527dd7cddfSDavid du Colombier { 5533ff48bf5SDavid du Colombier Udp4hdr *h4; 5543ff48bf5SDavid du Colombier Udp6hdr *h6; 5557dd7cddfSDavid du Colombier uchar source[IPaddrlen], dest[IPaddrlen]; 5567dd7cddfSDavid du Colombier ushort psource, pdest; 5577dd7cddfSDavid du Colombier Conv *s, **p; 5583ff48bf5SDavid du Colombier int version; 5597dd7cddfSDavid du Colombier 5603ff48bf5SDavid du Colombier h4 = (Udp4hdr*)(bp->rp); 5613ff48bf5SDavid du Colombier version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4; 5627dd7cddfSDavid du Colombier 5633ff48bf5SDavid du Colombier switch(version) { 5643ff48bf5SDavid du Colombier case V4: 5653ff48bf5SDavid du Colombier v4tov6(dest, h4->udpdst); 5663ff48bf5SDavid du Colombier v4tov6(source, h4->udpsrc); 5673ff48bf5SDavid du Colombier psource = nhgets(h4->udpsport); 5683ff48bf5SDavid du Colombier pdest = nhgets(h4->udpdport); 5693ff48bf5SDavid du Colombier break; 5703ff48bf5SDavid du Colombier case V6: 5713ff48bf5SDavid du Colombier h6 = (Udp6hdr*)(bp->rp); 5723ff48bf5SDavid du Colombier ipmove(dest, h6->udpdst); 5733ff48bf5SDavid du Colombier ipmove(source, h6->udpsrc); 5743ff48bf5SDavid du Colombier psource = nhgets(h6->udpsport); 5753ff48bf5SDavid du Colombier pdest = nhgets(h6->udpdport); 5763ff48bf5SDavid du Colombier break; 5773ff48bf5SDavid du Colombier default: 5783ff48bf5SDavid du Colombier panic("udpadvise: version %d", version); 5793ff48bf5SDavid du Colombier return; /* to avoid a warning */ 5803ff48bf5SDavid du Colombier } 5817dd7cddfSDavid du Colombier 5827dd7cddfSDavid du Colombier /* Look for a connection */ 5837dd7cddfSDavid du Colombier qlock(udp); 5847dd7cddfSDavid du Colombier for(p = udp->conv; *p; p++) { 5857dd7cddfSDavid du Colombier s = *p; 5867dd7cddfSDavid du Colombier if(s->rport == pdest) 5877dd7cddfSDavid du Colombier if(s->lport == psource) 5887dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dest) == 0) 5897dd7cddfSDavid du Colombier if(ipcmp(s->laddr, source) == 0){ 5903ff48bf5SDavid du Colombier if(s->ignoreadvice) 5913ff48bf5SDavid du Colombier break; 5927dd7cddfSDavid du Colombier qlock(s); 5937dd7cddfSDavid du Colombier qunlock(udp); 5947dd7cddfSDavid du Colombier qhangup(s->rq, msg); 5957dd7cddfSDavid du Colombier qhangup(s->wq, msg); 5967dd7cddfSDavid du Colombier qunlock(s); 5977dd7cddfSDavid du Colombier freeblist(bp); 5987dd7cddfSDavid du Colombier return; 5997dd7cddfSDavid du Colombier } 6007dd7cddfSDavid du Colombier } 6017dd7cddfSDavid du Colombier qunlock(udp); 6027dd7cddfSDavid du Colombier freeblist(bp); 6037dd7cddfSDavid du Colombier } 6047dd7cddfSDavid du Colombier 6057dd7cddfSDavid du Colombier int 6067dd7cddfSDavid du Colombier udpstats(Proto *udp, char *buf, int len) 6077dd7cddfSDavid du Colombier { 60880ee5cbfSDavid du Colombier Udppriv *upriv; 6097dd7cddfSDavid du Colombier 61080ee5cbfSDavid du Colombier upriv = udp->priv; 6119a747e4fSDavid du Colombier return snprint(buf, len, "InDatagrams: %lud\nNoPorts: %lud\nInErrors: %lud\nOutDatagrams: %lud\n", 61280ee5cbfSDavid du Colombier upriv->ustats.udpInDatagrams, 61380ee5cbfSDavid du Colombier upriv->ustats.udpNoPorts, 61480ee5cbfSDavid du Colombier upriv->ustats.udpInErrors, 61580ee5cbfSDavid du Colombier upriv->ustats.udpOutDatagrams); 6167dd7cddfSDavid du Colombier } 6177dd7cddfSDavid du Colombier 6187dd7cddfSDavid du Colombier void 6197dd7cddfSDavid du Colombier udpinit(Fs *fs) 6207dd7cddfSDavid du Colombier { 6217dd7cddfSDavid du Colombier Proto *udp; 6227dd7cddfSDavid du Colombier 6237dd7cddfSDavid du Colombier udp = smalloc(sizeof(Proto)); 6247dd7cddfSDavid du Colombier udp->priv = smalloc(sizeof(Udppriv)); 6257dd7cddfSDavid du Colombier udp->name = "udp"; 6267dd7cddfSDavid du Colombier udp->connect = udpconnect; 6277dd7cddfSDavid du Colombier udp->announce = udpannounce; 6287dd7cddfSDavid du Colombier udp->ctl = udpctl; 6297dd7cddfSDavid du Colombier udp->state = udpstate; 6307dd7cddfSDavid du Colombier udp->create = udpcreate; 6317dd7cddfSDavid du Colombier udp->close = udpclose; 6327dd7cddfSDavid du Colombier udp->rcv = udpiput; 6337dd7cddfSDavid du Colombier udp->advise = udpadvise; 6347dd7cddfSDavid du Colombier udp->stats = udpstats; 6357dd7cddfSDavid du Colombier udp->ipproto = IP_UDPPROTO; 6367dd7cddfSDavid du Colombier udp->nc = Nchans; 6377dd7cddfSDavid du Colombier udp->ptclsize = sizeof(Udpcb); 6387dd7cddfSDavid du Colombier 6397dd7cddfSDavid du Colombier Fsproto(fs, udp); 6407dd7cddfSDavid du Colombier } 641