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,
26dc5a79c1SDavid du Colombier UDP_USEAD7 = 52,
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier Udprxms = 200,
297dd7cddfSDavid du Colombier Udptickms = 100,
307dd7cddfSDavid du Colombier Udpmaxxmit = 10,
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier
333ff48bf5SDavid du Colombier typedef struct Udp4hdr Udp4hdr;
343ff48bf5SDavid du Colombier struct Udp4hdr
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier /* ip header */
377dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */
387dd7cddfSDavid du Colombier uchar tos; /* Type of service */
397dd7cddfSDavid du Colombier uchar length[2]; /* packet length */
407dd7cddfSDavid du Colombier uchar id[2]; /* Identification */
417dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */
427dd7cddfSDavid du Colombier uchar Unused;
437dd7cddfSDavid du Colombier uchar udpproto; /* Protocol */
447dd7cddfSDavid du Colombier uchar udpplen[2]; /* Header plus data length */
453ff48bf5SDavid du Colombier uchar udpsrc[IPv4addrlen]; /* Ip source */
463ff48bf5SDavid du Colombier uchar udpdst[IPv4addrlen]; /* Ip destination */
473ff48bf5SDavid du Colombier
483ff48bf5SDavid du Colombier /* udp header */
493ff48bf5SDavid du Colombier uchar udpsport[2]; /* Source port */
503ff48bf5SDavid du Colombier uchar udpdport[2]; /* Destination port */
513ff48bf5SDavid du Colombier uchar udplen[2]; /* data length */
523ff48bf5SDavid du Colombier uchar udpcksum[2]; /* Checksum */
533ff48bf5SDavid du Colombier };
543ff48bf5SDavid du Colombier
553ff48bf5SDavid du Colombier typedef struct Udp6hdr Udp6hdr;
563ff48bf5SDavid du Colombier struct Udp6hdr {
573ff48bf5SDavid du Colombier uchar viclfl[4];
583ff48bf5SDavid du Colombier uchar len[2];
593ff48bf5SDavid du Colombier uchar nextheader;
603ff48bf5SDavid du Colombier uchar hoplimit;
613ff48bf5SDavid du Colombier uchar udpsrc[IPaddrlen];
623ff48bf5SDavid du Colombier uchar udpdst[IPaddrlen];
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier /* udp header */
657dd7cddfSDavid du Colombier uchar udpsport[2]; /* Source port */
667dd7cddfSDavid du Colombier uchar udpdport[2]; /* Destination port */
677dd7cddfSDavid du Colombier uchar udplen[2]; /* data length */
687dd7cddfSDavid du Colombier uchar udpcksum[2]; /* Checksum */
697dd7cddfSDavid du Colombier };
707dd7cddfSDavid du Colombier
7159cc4ca5SDavid du Colombier /* MIB II counters */
7280ee5cbfSDavid du Colombier typedef struct Udpstats Udpstats;
7380ee5cbfSDavid du Colombier struct Udpstats
7480ee5cbfSDavid du Colombier {
75*5e27dea9SDavid du Colombier uvlong udpInDatagrams;
7680ee5cbfSDavid du Colombier ulong udpNoPorts;
7780ee5cbfSDavid du Colombier ulong udpInErrors;
78*5e27dea9SDavid du Colombier uvlong udpOutDatagrams;
797dd7cddfSDavid du Colombier };
807dd7cddfSDavid du Colombier
817dd7cddfSDavid du Colombier typedef struct Udppriv Udppriv;
827dd7cddfSDavid du Colombier struct Udppriv
837dd7cddfSDavid du Colombier {
8480ee5cbfSDavid du Colombier Ipht ht;
8580ee5cbfSDavid du Colombier
8680ee5cbfSDavid du Colombier /* MIB counters */
8780ee5cbfSDavid du Colombier Udpstats ustats;
8880ee5cbfSDavid du Colombier
8980ee5cbfSDavid du Colombier /* non-MIB stats */
9080ee5cbfSDavid du Colombier ulong csumerr; /* checksum errors */
9180ee5cbfSDavid du Colombier ulong lenerr; /* short packet */
927dd7cddfSDavid du Colombier };
937dd7cddfSDavid du Colombier
943ff48bf5SDavid du Colombier void (*etherprofiler)(char *name, int qlen);
95e6c6b7f8SDavid du Colombier void udpkick(void *x, Block *bp);
963ff48bf5SDavid du Colombier
977dd7cddfSDavid du Colombier /*
987dd7cddfSDavid du Colombier * protocol specific part of Conv
997dd7cddfSDavid du Colombier */
1007dd7cddfSDavid du Colombier typedef struct Udpcb Udpcb;
1017dd7cddfSDavid du Colombier struct Udpcb
1027dd7cddfSDavid du Colombier {
1037dd7cddfSDavid du Colombier QLock;
1047dd7cddfSDavid du Colombier uchar headers;
1057dd7cddfSDavid du Colombier };
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier static char*
udpconnect(Conv * c,char ** argv,int argc)1087dd7cddfSDavid du Colombier udpconnect(Conv *c, char **argv, int argc)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier char *e;
11180ee5cbfSDavid du Colombier Udppriv *upriv;
1127dd7cddfSDavid du Colombier
11380ee5cbfSDavid du Colombier upriv = c->p->priv;
1147dd7cddfSDavid du Colombier e = Fsstdconnect(c, argv, argc);
1157dd7cddfSDavid du Colombier Fsconnected(c, e);
1163ff48bf5SDavid du Colombier if(e != nil)
1177dd7cddfSDavid du Colombier return e;
1183ff48bf5SDavid du Colombier
1193ff48bf5SDavid du Colombier iphtadd(&upriv->ht, c);
1203ff48bf5SDavid du Colombier return nil;
1217dd7cddfSDavid du Colombier }
1227dd7cddfSDavid du Colombier
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier static int
udpstate(Conv * c,char * state,int n)1257dd7cddfSDavid du Colombier udpstate(Conv *c, char *state, int n)
1267dd7cddfSDavid du Colombier {
12703a1fc68SDavid du Colombier return snprint(state, n, "%s qin %d qout %d\n",
1284fec87e5SDavid du Colombier c->inuse ? "Open" : "Closed",
1294fec87e5SDavid du Colombier c->rq ? qlen(c->rq) : 0,
1304fec87e5SDavid du Colombier c->wq ? qlen(c->wq) : 0
1314fec87e5SDavid du Colombier );
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier static char*
udpannounce(Conv * c,char ** argv,int argc)1357dd7cddfSDavid du Colombier udpannounce(Conv *c, char** argv, int argc)
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier char *e;
13880ee5cbfSDavid du Colombier Udppriv *upriv;
1397dd7cddfSDavid du Colombier
14080ee5cbfSDavid du Colombier upriv = c->p->priv;
1417dd7cddfSDavid du Colombier e = Fsstdannounce(c, argv, argc);
1427dd7cddfSDavid du Colombier if(e != nil)
1437dd7cddfSDavid du Colombier return e;
1447dd7cddfSDavid du Colombier Fsconnected(c, nil);
14580ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c);
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier return nil;
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier static void
udpcreate(Conv * c)1517dd7cddfSDavid du Colombier udpcreate(Conv *c)
1527dd7cddfSDavid du Colombier {
1533ff48bf5SDavid du Colombier c->rq = qopen(128*1024, Qmsg, 0, 0);
154e6c6b7f8SDavid du Colombier c->wq = qbypass(udpkick, c);
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier
1577dd7cddfSDavid du Colombier static void
udpclose(Conv * c)1587dd7cddfSDavid du Colombier udpclose(Conv *c)
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier Udpcb *ucb;
16180ee5cbfSDavid du Colombier Udppriv *upriv;
16280ee5cbfSDavid du Colombier
16380ee5cbfSDavid du Colombier upriv = c->p->priv;
16480ee5cbfSDavid du Colombier iphtrem(&upriv->ht, c);
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier c->state = 0;
1677dd7cddfSDavid du Colombier qclose(c->rq);
1687dd7cddfSDavid du Colombier qclose(c->wq);
1697dd7cddfSDavid du Colombier qclose(c->eq);
1707dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
1717dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr);
1727dd7cddfSDavid du Colombier c->lport = 0;
1737dd7cddfSDavid du Colombier c->rport = 0;
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl;
1767dd7cddfSDavid du Colombier ucb->headers = 0;
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier void
udpkick(void * x,Block * bp)180e6c6b7f8SDavid du Colombier udpkick(void *x, Block *bp)
1817dd7cddfSDavid du Colombier {
1823ff48bf5SDavid du Colombier Conv *c = x;
1833ff48bf5SDavid du Colombier Udp4hdr *uh4;
1843ff48bf5SDavid du Colombier Udp6hdr *uh6;
1857dd7cddfSDavid du Colombier ushort rport;
1867dd7cddfSDavid du Colombier uchar laddr[IPaddrlen], raddr[IPaddrlen];
1877dd7cddfSDavid du Colombier Udpcb *ucb;
1887dd7cddfSDavid du Colombier int dlen, ptcllen;
1897dd7cddfSDavid du Colombier Udppriv *upriv;
1907dd7cddfSDavid du Colombier Fs *f;
1913ff48bf5SDavid du Colombier int version;
192a6a9e072SDavid du Colombier Conv *rc;
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier upriv = c->p->priv;
1957dd7cddfSDavid du Colombier f = c->p->f;
1967dd7cddfSDavid du Colombier
1977ec5746aSDavid du Colombier // netlog(c->p->f, Logudp, "udp: kick\n"); /* frequent and uninteresting */
1987dd7cddfSDavid du Colombier if(bp == nil)
1997dd7cddfSDavid du Colombier return;
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl;
2027dd7cddfSDavid du Colombier switch(ucb->headers) {
203dc5a79c1SDavid du Colombier case 7:
204dc5a79c1SDavid du Colombier /* get user specified addresses */
205dc5a79c1SDavid du Colombier bp = pullupblock(bp, UDP_USEAD7);
206dc5a79c1SDavid du Colombier if(bp == nil)
207dc5a79c1SDavid du Colombier return;
208dc5a79c1SDavid du Colombier ipmove(raddr, bp->rp);
209dc5a79c1SDavid du Colombier bp->rp += IPaddrlen;
210dc5a79c1SDavid du Colombier ipmove(laddr, bp->rp);
211dc5a79c1SDavid du Colombier bp->rp += IPaddrlen;
212dc5a79c1SDavid du Colombier /* pick interface closest to dest */
213dc5a79c1SDavid du Colombier if(ipforme(f, laddr) != Runi)
214dc5a79c1SDavid du Colombier findlocalip(f, laddr, raddr);
215dc5a79c1SDavid du Colombier bp->rp += IPaddrlen; /* Ignore ifc address */
216dc5a79c1SDavid du Colombier rport = nhgets(bp->rp);
217dc5a79c1SDavid du Colombier bp->rp += 2+2; /* Ignore local port */
218dc5a79c1SDavid du Colombier break;
2197dd7cddfSDavid du Colombier default:
2207dd7cddfSDavid du Colombier rport = 0;
2217dd7cddfSDavid du Colombier break;
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier
224dc5a79c1SDavid du Colombier if(ucb->headers) {
225f2c197d9SDavid du Colombier if(memcmp(laddr, v4prefix, IPv4off) == 0
226f2c197d9SDavid du Colombier || ipcmp(laddr, IPnoaddr) == 0)
2273ff48bf5SDavid du Colombier version = 4;
2283ff48bf5SDavid du Colombier else
2293ff48bf5SDavid du Colombier version = 6;
230dc5a79c1SDavid du Colombier } else {
2313ff48bf5SDavid du Colombier if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
232f2c197d9SDavid du Colombier memcmp(c->laddr, v4prefix, IPv4off) == 0)
233f2c197d9SDavid du Colombier || ipcmp(c->raddr, IPnoaddr) == 0)
2343ff48bf5SDavid du Colombier version = 4;
2353ff48bf5SDavid du Colombier else
2363ff48bf5SDavid du Colombier version = 6;
2373ff48bf5SDavid du Colombier }
2383ff48bf5SDavid du Colombier
2397dd7cddfSDavid du Colombier dlen = blocklen(bp);
2407dd7cddfSDavid du Colombier
2413ff48bf5SDavid du Colombier /* fill in pseudo header and compute checksum */
2423ff48bf5SDavid du Colombier switch(version){
2433ff48bf5SDavid du Colombier case V4:
2443ff48bf5SDavid du Colombier bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
2457dd7cddfSDavid du Colombier if(bp == nil)
2467dd7cddfSDavid du Colombier return;
2477dd7cddfSDavid du Colombier
2483ff48bf5SDavid du Colombier uh4 = (Udp4hdr *)(bp->rp);
2493ff48bf5SDavid du Colombier ptcllen = dlen + UDP_UDPHDR_SZ;
2503ff48bf5SDavid du Colombier uh4->Unused = 0;
2513ff48bf5SDavid du Colombier uh4->udpproto = IP_UDPPROTO;
2523ff48bf5SDavid du Colombier uh4->frag[0] = 0;
2533ff48bf5SDavid du Colombier uh4->frag[1] = 0;
2543ff48bf5SDavid du Colombier hnputs(uh4->udpplen, ptcllen);
255dc5a79c1SDavid du Colombier if(ucb->headers) {
2563ff48bf5SDavid du Colombier v6tov4(uh4->udpdst, raddr);
2573ff48bf5SDavid du Colombier hnputs(uh4->udpdport, rport);
2583ff48bf5SDavid du Colombier v6tov4(uh4->udpsrc, laddr);
259a6a9e072SDavid du Colombier rc = nil;
2603ff48bf5SDavid du Colombier } else {
2613ff48bf5SDavid du Colombier v6tov4(uh4->udpdst, c->raddr);
2623ff48bf5SDavid du Colombier hnputs(uh4->udpdport, c->rport);
2637dd7cddfSDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0)
2647dd7cddfSDavid du Colombier findlocalip(f, c->laddr, c->raddr);
2653ff48bf5SDavid du Colombier v6tov4(uh4->udpsrc, c->laddr);
266a6a9e072SDavid du Colombier rc = c;
2673ff48bf5SDavid du Colombier }
2683ff48bf5SDavid du Colombier hnputs(uh4->udpsport, c->lport);
2693ff48bf5SDavid du Colombier hnputs(uh4->udplen, ptcllen);
2703ff48bf5SDavid du Colombier uh4->udpcksum[0] = 0;
2713ff48bf5SDavid du Colombier uh4->udpcksum[1] = 0;
2723ff48bf5SDavid du Colombier hnputs(uh4->udpcksum,
2733ff48bf5SDavid du Colombier ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
2743ff48bf5SDavid du Colombier uh4->vihl = IP_VER4;
275a6a9e072SDavid du Colombier ipoput4(f, bp, 0, c->ttl, c->tos, rc);
2767dd7cddfSDavid du Colombier break;
2773ff48bf5SDavid du Colombier
2783ff48bf5SDavid du Colombier case V6:
2793ff48bf5SDavid du Colombier bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
2803ff48bf5SDavid du Colombier if(bp == nil)
2813ff48bf5SDavid du Colombier return;
2823ff48bf5SDavid du Colombier
28341dd6b47SDavid du Colombier /*
28441dd6b47SDavid du Colombier * using the v6 ip header to create pseudo header
28541dd6b47SDavid du Colombier * first then reset it to the normal ip header
28641dd6b47SDavid du Colombier */
2873ff48bf5SDavid du Colombier uh6 = (Udp6hdr *)(bp->rp);
2883ff48bf5SDavid du Colombier memset(uh6, 0, 8);
2893ff48bf5SDavid du Colombier ptcllen = dlen + UDP_UDPHDR_SZ;
2903ff48bf5SDavid du Colombier hnputl(uh6->viclfl, ptcllen);
2913ff48bf5SDavid du Colombier uh6->hoplimit = IP_UDPPROTO;
292dc5a79c1SDavid du Colombier if(ucb->headers) {
2933ff48bf5SDavid du Colombier ipmove(uh6->udpdst, raddr);
2943ff48bf5SDavid du Colombier hnputs(uh6->udpdport, rport);
2953ff48bf5SDavid du Colombier ipmove(uh6->udpsrc, laddr);
296a6a9e072SDavid du Colombier rc = nil;
2973ff48bf5SDavid du Colombier } else {
2983ff48bf5SDavid du Colombier ipmove(uh6->udpdst, c->raddr);
2993ff48bf5SDavid du Colombier hnputs(uh6->udpdport, c->rport);
3003ff48bf5SDavid du Colombier if(ipcmp(c->laddr, IPnoaddr) == 0)
3013ff48bf5SDavid du Colombier findlocalip(f, c->laddr, c->raddr);
3023ff48bf5SDavid du Colombier ipmove(uh6->udpsrc, c->laddr);
303a6a9e072SDavid du Colombier rc = c;
3047dd7cddfSDavid du Colombier }
3053ff48bf5SDavid du Colombier hnputs(uh6->udpsport, c->lport);
3063ff48bf5SDavid du Colombier hnputs(uh6->udplen, ptcllen);
3073ff48bf5SDavid du Colombier uh6->udpcksum[0] = 0;
3083ff48bf5SDavid du Colombier uh6->udpcksum[1] = 0;
3093ff48bf5SDavid du Colombier hnputs(uh6->udpcksum,
3103ff48bf5SDavid du Colombier ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
3113ff48bf5SDavid du Colombier memset(uh6, 0, 8);
3123ff48bf5SDavid du Colombier uh6->viclfl[0] = IP_VER6;
3133ff48bf5SDavid du Colombier hnputs(uh6->len, ptcllen);
3143ff48bf5SDavid du Colombier uh6->nextheader = IP_UDPPROTO;
315a6a9e072SDavid du Colombier ipoput6(f, bp, 0, c->ttl, c->tos, rc);
3163ff48bf5SDavid du Colombier break;
3177dd7cddfSDavid du Colombier
3183ff48bf5SDavid du Colombier default:
3193ff48bf5SDavid du Colombier panic("udpkick: version %d", version);
3203ff48bf5SDavid du Colombier }
32180ee5cbfSDavid du Colombier upriv->ustats.udpOutDatagrams++;
32280ee5cbfSDavid du Colombier }
32380ee5cbfSDavid du Colombier
3247dd7cddfSDavid du Colombier void
udpiput(Proto * udp,Ipifc * ifc,Block * bp)3259a747e4fSDavid du Colombier udpiput(Proto *udp, Ipifc *ifc, Block *bp)
3267dd7cddfSDavid du Colombier {
3273ff48bf5SDavid du Colombier int len;
3283ff48bf5SDavid du Colombier Udp4hdr *uh4;
3293ff48bf5SDavid du Colombier Udp6hdr *uh6;
33080ee5cbfSDavid du Colombier Conv *c;
3317dd7cddfSDavid du Colombier Udpcb *ucb;
3327dd7cddfSDavid du Colombier uchar raddr[IPaddrlen], laddr[IPaddrlen];
3337dd7cddfSDavid du Colombier ushort rport, lport;
3347dd7cddfSDavid du Colombier Udppriv *upriv;
3357dd7cddfSDavid du Colombier Fs *f;
3363ff48bf5SDavid du Colombier int version;
3373ff48bf5SDavid du Colombier int ottl, oviclfl, olen;
338dc5a79c1SDavid du Colombier uchar *p;
3397dd7cddfSDavid du Colombier
3407dd7cddfSDavid du Colombier upriv = udp->priv;
3417dd7cddfSDavid du Colombier f = udp->f;
34280ee5cbfSDavid du Colombier upriv->ustats.udpInDatagrams++;
3437dd7cddfSDavid du Colombier
3443ff48bf5SDavid du Colombier uh4 = (Udp4hdr*)(bp->rp);
3453ff48bf5SDavid du Colombier version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
3467dd7cddfSDavid du Colombier
3473ff48bf5SDavid du Colombier /* Put back pseudo header for checksum
3483ff48bf5SDavid du Colombier * (remember old values for icmpnoconv()) */
3493ff48bf5SDavid du Colombier switch(version) {
3503ff48bf5SDavid du Colombier case V4:
3513ff48bf5SDavid du Colombier ottl = uh4->Unused;
3523ff48bf5SDavid du Colombier uh4->Unused = 0;
3533ff48bf5SDavid du Colombier len = nhgets(uh4->udplen);
3543ff48bf5SDavid du Colombier olen = nhgets(uh4->udpplen);
3553ff48bf5SDavid du Colombier hnputs(uh4->udpplen, len);
3567dd7cddfSDavid du Colombier
3573ff48bf5SDavid du Colombier v4tov6(raddr, uh4->udpsrc);
3583ff48bf5SDavid du Colombier v4tov6(laddr, uh4->udpdst);
3593ff48bf5SDavid du Colombier lport = nhgets(uh4->udpdport);
3603ff48bf5SDavid du Colombier rport = nhgets(uh4->udpsport);
3617dd7cddfSDavid du Colombier
3623ff48bf5SDavid du Colombier if(nhgets(uh4->udpcksum)) {
3633ff48bf5SDavid du Colombier if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
36480ee5cbfSDavid du Colombier upriv->ustats.udpInErrors++;
3657dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: checksum error %I\n", raddr);
3667dd7cddfSDavid du Colombier DPRINT("udp: checksum error %I\n", raddr);
3677dd7cddfSDavid du Colombier freeblist(bp);
3687dd7cddfSDavid du Colombier return;
3697dd7cddfSDavid du Colombier }
3707dd7cddfSDavid du Colombier }
3713ff48bf5SDavid du Colombier uh4->Unused = ottl;
3723ff48bf5SDavid du Colombier hnputs(uh4->udpplen, olen);
3733ff48bf5SDavid du Colombier break;
3743ff48bf5SDavid du Colombier case V6:
3753ff48bf5SDavid du Colombier uh6 = (Udp6hdr*)(bp->rp);
3763ff48bf5SDavid du Colombier len = nhgets(uh6->udplen);
3773ff48bf5SDavid du Colombier oviclfl = nhgetl(uh6->viclfl);
3783ff48bf5SDavid du Colombier olen = nhgets(uh6->len);
3793ff48bf5SDavid du Colombier ottl = uh6->hoplimit;
3803ff48bf5SDavid du Colombier ipmove(raddr, uh6->udpsrc);
3813ff48bf5SDavid du Colombier ipmove(laddr, uh6->udpdst);
3823ff48bf5SDavid du Colombier lport = nhgets(uh6->udpdport);
3833ff48bf5SDavid du Colombier rport = nhgets(uh6->udpsport);
3843ff48bf5SDavid du Colombier memset(uh6, 0, 8);
3853ff48bf5SDavid du Colombier hnputl(uh6->viclfl, len);
3863ff48bf5SDavid du Colombier uh6->hoplimit = IP_UDPPROTO;
3873ff48bf5SDavid du Colombier if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
3883ff48bf5SDavid du Colombier upriv->ustats.udpInErrors++;
3893ff48bf5SDavid du Colombier netlog(f, Logudp, "udp: checksum error %I\n", raddr);
3903ff48bf5SDavid du Colombier DPRINT("udp: checksum error %I\n", raddr);
3913ff48bf5SDavid du Colombier freeblist(bp);
3923ff48bf5SDavid du Colombier return;
3933ff48bf5SDavid du Colombier }
3943ff48bf5SDavid du Colombier hnputl(uh6->viclfl, oviclfl);
3953ff48bf5SDavid du Colombier hnputs(uh6->len, olen);
3963ff48bf5SDavid du Colombier uh6->nextheader = IP_UDPPROTO;
3973ff48bf5SDavid du Colombier uh6->hoplimit = ottl;
3983ff48bf5SDavid du Colombier break;
3993ff48bf5SDavid du Colombier default:
4003ff48bf5SDavid du Colombier panic("udpiput: version %d", version);
4013ff48bf5SDavid du Colombier return; /* to avoid a warning */
4023ff48bf5SDavid du Colombier }
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier qlock(udp);
4057dd7cddfSDavid du Colombier
40680ee5cbfSDavid du Colombier c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
4077dd7cddfSDavid du Colombier if(c == nil){
408ac020a8fSDavid du Colombier /* no conversation found */
40980ee5cbfSDavid du Colombier upriv->ustats.udpNoPorts++;
4107dd7cddfSDavid du Colombier qunlock(udp);
4117dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
4127dd7cddfSDavid du Colombier laddr, lport);
4133ff48bf5SDavid du Colombier
4143ff48bf5SDavid du Colombier switch(version){
4153ff48bf5SDavid du Colombier case V4:
4167dd7cddfSDavid du Colombier icmpnoconv(f, bp);
4173ff48bf5SDavid du Colombier break;
4183ff48bf5SDavid du Colombier case V6:
419f2c197d9SDavid du Colombier icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0);
4203ff48bf5SDavid du Colombier break;
4213ff48bf5SDavid du Colombier default:
4223ff48bf5SDavid du Colombier panic("udpiput2: version %d", version);
4233ff48bf5SDavid du Colombier }
4243ff48bf5SDavid du Colombier
4257dd7cddfSDavid du Colombier freeblist(bp);
4267dd7cddfSDavid du Colombier return;
4277dd7cddfSDavid du Colombier }
42880ee5cbfSDavid du Colombier ucb = (Udpcb*)c->ptcl;
42980ee5cbfSDavid du Colombier
43080ee5cbfSDavid du Colombier if(c->state == Announced){
43180ee5cbfSDavid du Colombier if(ucb->headers == 0){
43280ee5cbfSDavid du Colombier /* create a new conversation */
4333ff48bf5SDavid du Colombier if(ipforme(f, laddr) != Runi) {
4343ff48bf5SDavid du Colombier switch(version){
4353ff48bf5SDavid du Colombier case V4:
4369a747e4fSDavid du Colombier v4tov6(laddr, ifc->lifc->local);
4373ff48bf5SDavid du Colombier break;
4383ff48bf5SDavid du Colombier case V6:
4393ff48bf5SDavid du Colombier ipmove(laddr, ifc->lifc->local);
4403ff48bf5SDavid du Colombier break;
4413ff48bf5SDavid du Colombier default:
4423ff48bf5SDavid du Colombier panic("udpiput3: version %d", version);
4433ff48bf5SDavid du Colombier }
4443ff48bf5SDavid du Colombier }
4453ff48bf5SDavid du Colombier c = Fsnewcall(c, raddr, rport, laddr, lport, version);
44680ee5cbfSDavid du Colombier if(c == nil){
44780ee5cbfSDavid du Colombier qunlock(udp);
44880ee5cbfSDavid du Colombier freeblist(bp);
44980ee5cbfSDavid du Colombier return;
45080ee5cbfSDavid du Colombier }
45180ee5cbfSDavid du Colombier iphtadd(&upriv->ht, c);
45280ee5cbfSDavid du Colombier ucb = (Udpcb*)c->ptcl;
45380ee5cbfSDavid du Colombier }
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier
4567dd7cddfSDavid du Colombier qlock(c);
4577dd7cddfSDavid du Colombier qunlock(udp);
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier /*
4607dd7cddfSDavid du Colombier * Trim the packet down to data size
4617dd7cddfSDavid du Colombier */
4623ff48bf5SDavid du Colombier len -= UDP_UDPHDR_SZ;
4633ff48bf5SDavid du Colombier switch(version){
4643ff48bf5SDavid du Colombier case V4:
4653ff48bf5SDavid du Colombier bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
4663ff48bf5SDavid du Colombier break;
4673ff48bf5SDavid du Colombier case V6:
4683ff48bf5SDavid du Colombier bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
4693ff48bf5SDavid du Colombier break;
4703ff48bf5SDavid du Colombier default:
4713ff48bf5SDavid du Colombier bp = nil;
4723ff48bf5SDavid du Colombier panic("udpiput4: version %d", version);
4733ff48bf5SDavid du Colombier }
4747dd7cddfSDavid du Colombier if(bp == nil){
4757dd7cddfSDavid du Colombier qunlock(c);
4767dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
4777dd7cddfSDavid du Colombier laddr, lport);
47880ee5cbfSDavid du Colombier upriv->lenerr++;
4797dd7cddfSDavid du Colombier return;
4807dd7cddfSDavid du Colombier }
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
4837dd7cddfSDavid du Colombier laddr, lport, len);
4847dd7cddfSDavid du Colombier
4857dd7cddfSDavid du Colombier switch(ucb->headers){
486dc5a79c1SDavid du Colombier case 7:
487dc5a79c1SDavid du Colombier /* pass the src address */
488dc5a79c1SDavid du Colombier bp = padblock(bp, UDP_USEAD7);
489dc5a79c1SDavid du Colombier p = bp->rp;
490dc5a79c1SDavid du Colombier ipmove(p, raddr); p += IPaddrlen;
491dc5a79c1SDavid du Colombier ipmove(p, laddr); p += IPaddrlen;
492dc5a79c1SDavid du Colombier ipmove(p, ifc->lifc->local); p += IPaddrlen;
493dc5a79c1SDavid du Colombier hnputs(p, rport); p += 2;
494dc5a79c1SDavid du Colombier hnputs(p, lport);
495dc5a79c1SDavid du Colombier break;
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier if(bp->next)
4997dd7cddfSDavid du Colombier bp = concatblock(bp);
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier if(qfull(c->rq)){
5027dd7cddfSDavid du Colombier qunlock(c);
5037dd7cddfSDavid du Colombier netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
5047dd7cddfSDavid du Colombier laddr, lport);
5057dd7cddfSDavid du Colombier freeblist(bp);
5067dd7cddfSDavid du Colombier return;
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier
5097dd7cddfSDavid du Colombier qpass(c->rq, bp);
5107dd7cddfSDavid du Colombier qunlock(c);
5117dd7cddfSDavid du Colombier
5127dd7cddfSDavid du Colombier }
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier char*
udpctl(Conv * c,char ** f,int n)5157dd7cddfSDavid du Colombier udpctl(Conv *c, char **f, int n)
5167dd7cddfSDavid du Colombier {
5177dd7cddfSDavid du Colombier Udpcb *ucb;
5187dd7cddfSDavid du Colombier
5197dd7cddfSDavid du Colombier ucb = (Udpcb*)c->ptcl;
5207dd7cddfSDavid du Colombier if(n == 1){
521f2714ceaSDavid du Colombier if(strcmp(f[0], "headers") == 0){
52287dfdc75SDavid du Colombier ucb->headers = 7; /* new headers format */
5237dd7cddfSDavid du Colombier return nil;
5247dd7cddfSDavid du Colombier }
5257dd7cddfSDavid du Colombier }
5267dd7cddfSDavid du Colombier return "unknown control request";
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier
5297dd7cddfSDavid du Colombier void
udpadvise(Proto * udp,Block * bp,char * msg)5307dd7cddfSDavid du Colombier udpadvise(Proto *udp, Block *bp, char *msg)
5317dd7cddfSDavid du Colombier {
5323ff48bf5SDavid du Colombier Udp4hdr *h4;
5333ff48bf5SDavid du Colombier Udp6hdr *h6;
5347dd7cddfSDavid du Colombier uchar source[IPaddrlen], dest[IPaddrlen];
5357dd7cddfSDavid du Colombier ushort psource, pdest;
5367dd7cddfSDavid du Colombier Conv *s, **p;
5373ff48bf5SDavid du Colombier int version;
5387dd7cddfSDavid du Colombier
5393ff48bf5SDavid du Colombier h4 = (Udp4hdr*)(bp->rp);
5403ff48bf5SDavid du Colombier version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
5417dd7cddfSDavid du Colombier
5423ff48bf5SDavid du Colombier switch(version) {
5433ff48bf5SDavid du Colombier case V4:
5443ff48bf5SDavid du Colombier v4tov6(dest, h4->udpdst);
5453ff48bf5SDavid du Colombier v4tov6(source, h4->udpsrc);
5463ff48bf5SDavid du Colombier psource = nhgets(h4->udpsport);
5473ff48bf5SDavid du Colombier pdest = nhgets(h4->udpdport);
5483ff48bf5SDavid du Colombier break;
5493ff48bf5SDavid du Colombier case V6:
5503ff48bf5SDavid du Colombier h6 = (Udp6hdr*)(bp->rp);
5513ff48bf5SDavid du Colombier ipmove(dest, h6->udpdst);
5523ff48bf5SDavid du Colombier ipmove(source, h6->udpsrc);
5533ff48bf5SDavid du Colombier psource = nhgets(h6->udpsport);
5543ff48bf5SDavid du Colombier pdest = nhgets(h6->udpdport);
5553ff48bf5SDavid du Colombier break;
5563ff48bf5SDavid du Colombier default:
5573ff48bf5SDavid du Colombier panic("udpadvise: version %d", version);
5583ff48bf5SDavid du Colombier return; /* to avoid a warning */
5593ff48bf5SDavid du Colombier }
5607dd7cddfSDavid du Colombier
5617dd7cddfSDavid du Colombier /* Look for a connection */
5627dd7cddfSDavid du Colombier qlock(udp);
5637dd7cddfSDavid du Colombier for(p = udp->conv; *p; p++) {
5647dd7cddfSDavid du Colombier s = *p;
5657dd7cddfSDavid du Colombier if(s->rport == pdest)
5667dd7cddfSDavid du Colombier if(s->lport == psource)
5677dd7cddfSDavid du Colombier if(ipcmp(s->raddr, dest) == 0)
5687dd7cddfSDavid du Colombier if(ipcmp(s->laddr, source) == 0){
5693ff48bf5SDavid du Colombier if(s->ignoreadvice)
5703ff48bf5SDavid du Colombier break;
5717dd7cddfSDavid du Colombier qlock(s);
5727dd7cddfSDavid du Colombier qunlock(udp);
5737dd7cddfSDavid du Colombier qhangup(s->rq, msg);
5747dd7cddfSDavid du Colombier qhangup(s->wq, msg);
5757dd7cddfSDavid du Colombier qunlock(s);
5767dd7cddfSDavid du Colombier freeblist(bp);
5777dd7cddfSDavid du Colombier return;
5787dd7cddfSDavid du Colombier }
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier qunlock(udp);
5817dd7cddfSDavid du Colombier freeblist(bp);
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier
5847dd7cddfSDavid du Colombier int
udpstats(Proto * udp,char * buf,int len)5857dd7cddfSDavid du Colombier udpstats(Proto *udp, char *buf, int len)
5867dd7cddfSDavid du Colombier {
58780ee5cbfSDavid du Colombier Udppriv *upriv;
5887dd7cddfSDavid du Colombier
58980ee5cbfSDavid du Colombier upriv = udp->priv;
590*5e27dea9SDavid du Colombier return snprint(buf, len, "InDatagrams: %llud\nNoPorts: %lud\n"
591*5e27dea9SDavid du Colombier "InErrors: %lud\nOutDatagrams: %llud\n",
59280ee5cbfSDavid du Colombier upriv->ustats.udpInDatagrams,
59380ee5cbfSDavid du Colombier upriv->ustats.udpNoPorts,
59480ee5cbfSDavid du Colombier upriv->ustats.udpInErrors,
59580ee5cbfSDavid du Colombier upriv->ustats.udpOutDatagrams);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier
5987dd7cddfSDavid du Colombier void
udpinit(Fs * fs)5997dd7cddfSDavid du Colombier udpinit(Fs *fs)
6007dd7cddfSDavid du Colombier {
6017dd7cddfSDavid du Colombier Proto *udp;
6027dd7cddfSDavid du Colombier
6037dd7cddfSDavid du Colombier udp = smalloc(sizeof(Proto));
6047dd7cddfSDavid du Colombier udp->priv = smalloc(sizeof(Udppriv));
6057dd7cddfSDavid du Colombier udp->name = "udp";
6067dd7cddfSDavid du Colombier udp->connect = udpconnect;
6077dd7cddfSDavid du Colombier udp->announce = udpannounce;
6087dd7cddfSDavid du Colombier udp->ctl = udpctl;
6097dd7cddfSDavid du Colombier udp->state = udpstate;
6107dd7cddfSDavid du Colombier udp->create = udpcreate;
6117dd7cddfSDavid du Colombier udp->close = udpclose;
6127dd7cddfSDavid du Colombier udp->rcv = udpiput;
6137dd7cddfSDavid du Colombier udp->advise = udpadvise;
6147dd7cddfSDavid du Colombier udp->stats = udpstats;
6157dd7cddfSDavid du Colombier udp->ipproto = IP_UDPPROTO;
6167dd7cddfSDavid du Colombier udp->nc = Nchans;
6177dd7cddfSDavid du Colombier udp->ptclsize = sizeof(Udpcb);
6187dd7cddfSDavid du Colombier
6197dd7cddfSDavid du Colombier Fsproto(fs, udp);
6207dd7cddfSDavid du Colombier }
621