2 #include "../port/lib.h"
6 #include "../port/error.h"
12 #define DPRINT if(0)print
33 typedef struct Udp4hdr Udp4hdr;
37 uchar vihl; /* Version and header length */
38 uchar tos; /* Type of service */
39 uchar length[2]; /* packet length */
40 uchar id[2]; /* Identification */
41 uchar frag[2]; /* Fragment information */
43 uchar udpproto; /* Protocol */
44 uchar udpplen[2]; /* Header plus data length */
45 uchar udpsrc[IPv4addrlen]; /* Ip source */
46 uchar udpdst[IPv4addrlen]; /* Ip destination */
49 uchar udpsport[2]; /* Source port */
50 uchar udpdport[2]; /* Destination port */
51 uchar udplen[2]; /* data length */
52 uchar udpcksum[2]; /* Checksum */
55 typedef struct Udp6hdr Udp6hdr;
61 uchar udpsrc[IPaddrlen];
62 uchar udpdst[IPaddrlen];
65 uchar udpsport[2]; /* Source port */
66 uchar udpdport[2]; /* Destination port */
67 uchar udplen[2]; /* data length */
68 uchar udpcksum[2]; /* Checksum */
72 typedef struct Udpstats Udpstats;
75 uvlong udpInDatagrams;
78 uvlong udpOutDatagrams;
81 typedef struct Udppriv Udppriv;
90 ulong csumerr; /* checksum errors */
91 ulong lenerr; /* short packet */
94 void (*etherprofiler)(char *name, int qlen);
95 void udpkick(void *x, Block *bp);
98 * protocol specific part of Conv
100 typedef struct Udpcb Udpcb;
108 udpconnect(Conv *c, char **argv, int argc)
114 e = Fsstdconnect(c, argv, argc);
119 iphtadd(&upriv->ht, c);
125 udpstate(Conv *c, char *state, int n)
127 return snprint(state, n, "%s qin %d qout %d\n",
128 c->inuse ? "Open" : "Closed",
129 c->rq ? qlen(c->rq) : 0,
130 c->wq ? qlen(c->wq) : 0
135 udpannounce(Conv *c, char** argv, int argc)
141 e = Fsstdannounce(c, argv, argc);
145 iphtadd(&upriv->ht, c);
153 c->rq = qopen(512*1024, Qmsg, 0, 0);
154 c->wq = qbypass(udpkick, c);
164 iphtrem(&upriv->ht, c);
170 ipmove(c->laddr, IPnoaddr);
171 ipmove(c->raddr, IPnoaddr);
175 ucb = (Udpcb*)c->ptcl;
180 udpkick(void *x, Block *bp)
186 uchar laddr[IPaddrlen], raddr[IPaddrlen];
197 // netlog(c->p->f, Logudp, "udp: kick\n"); /* frequent and uninteresting */
201 ucb = (Udpcb*)c->ptcl;
202 switch(ucb->headers) {
204 /* get user specified addresses */
205 bp = pullupblock(bp, UDP_USEAD7);
208 ipmove(raddr, bp->rp);
210 ipmove(laddr, bp->rp);
212 /* pick interface closest to dest */
213 if(ipforme(f, laddr) != Runi)
214 findlocalip(f, laddr, raddr);
215 bp->rp += IPaddrlen; /* Ignore ifc address */
216 rport = nhgets(bp->rp);
217 bp->rp += 2+2; /* Ignore local port */
225 if(memcmp(laddr, v4prefix, IPv4off) == 0
226 || ipcmp(laddr, IPnoaddr) == 0)
231 if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
232 memcmp(c->laddr, v4prefix, IPv4off) == 0)
233 || ipcmp(c->raddr, IPnoaddr) == 0)
241 /* fill in pseudo header and compute checksum */
244 bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
245 uh4 = (Udp4hdr *)(bp->rp);
246 ptcllen = dlen + UDP_UDPHDR_SZ;
248 uh4->udpproto = IP_UDPPROTO;
251 hnputs(uh4->udpplen, ptcllen);
253 v6tov4(uh4->udpdst, raddr);
254 hnputs(uh4->udpdport, rport);
255 v6tov4(uh4->udpsrc, laddr);
258 v6tov4(uh4->udpdst, c->raddr);
259 hnputs(uh4->udpdport, c->rport);
260 if(ipcmp(c->laddr, IPnoaddr) == 0)
261 findlocalip(f, c->laddr, c->raddr);
262 v6tov4(uh4->udpsrc, c->laddr);
265 hnputs(uh4->udpsport, c->lport);
266 hnputs(uh4->udplen, ptcllen);
267 uh4->udpcksum[0] = 0;
268 uh4->udpcksum[1] = 0;
269 hnputs(uh4->udpcksum,
270 ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
272 ipoput4(f, bp, 0, c->ttl, c->tos, rc);
277 * using the v6 ip header to create pseudo header
278 * first then reset it to the normal ip header
280 bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
281 uh6 = (Udp6hdr *)(bp->rp);
283 ptcllen = dlen + UDP_UDPHDR_SZ;
284 hnputl(uh6->viclfl, ptcllen);
285 uh6->hoplimit = IP_UDPPROTO;
287 ipmove(uh6->udpdst, raddr);
288 hnputs(uh6->udpdport, rport);
289 ipmove(uh6->udpsrc, laddr);
292 ipmove(uh6->udpdst, c->raddr);
293 hnputs(uh6->udpdport, c->rport);
294 if(ipcmp(c->laddr, IPnoaddr) == 0)
295 findlocalip(f, c->laddr, c->raddr);
296 ipmove(uh6->udpsrc, c->laddr);
299 hnputs(uh6->udpsport, c->lport);
300 hnputs(uh6->udplen, ptcllen);
301 uh6->udpcksum[0] = 0;
302 uh6->udpcksum[1] = 0;
303 hnputs(uh6->udpcksum,
304 ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
306 uh6->viclfl[0] = IP_VER6;
307 hnputs(uh6->len, ptcllen);
308 uh6->nextheader = IP_UDPPROTO;
309 ipoput6(f, bp, 0, c->ttl, c->tos, rc);
313 panic("udpkick: version %d", version);
315 upriv->ustats.udpOutDatagrams++;
319 udpiput(Proto *udp, Ipifc *ifc, Block *bp)
326 uchar raddr[IPaddrlen], laddr[IPaddrlen];
331 int ottl, oviclfl, olen;
336 upriv->ustats.udpInDatagrams++;
338 uh4 = (Udp4hdr*)(bp->rp);
339 version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
341 /* Put back pseudo header for checksum
342 * (remember old values for icmpnoconv()) */
347 len = nhgets(uh4->udplen);
348 olen = nhgets(uh4->udpplen);
349 hnputs(uh4->udpplen, len);
351 v4tov6(raddr, uh4->udpsrc);
352 v4tov6(laddr, uh4->udpdst);
353 lport = nhgets(uh4->udpdport);
354 rport = nhgets(uh4->udpsport);
356 if(nhgets(uh4->udpcksum)) {
357 if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
358 upriv->ustats.udpInErrors++;
359 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
360 DPRINT("udp: checksum error %I\n", raddr);
366 hnputs(uh4->udpplen, olen);
369 uh6 = (Udp6hdr*)(bp->rp);
370 len = nhgets(uh6->udplen);
371 oviclfl = nhgetl(uh6->viclfl);
372 olen = nhgets(uh6->len);
373 ottl = uh6->hoplimit;
374 ipmove(raddr, uh6->udpsrc);
375 ipmove(laddr, uh6->udpdst);
376 lport = nhgets(uh6->udpdport);
377 rport = nhgets(uh6->udpsport);
379 hnputl(uh6->viclfl, len);
380 uh6->hoplimit = IP_UDPPROTO;
381 if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
382 upriv->ustats.udpInErrors++;
383 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
384 DPRINT("udp: checksum error %I\n", raddr);
388 hnputl(uh6->viclfl, oviclfl);
389 hnputs(uh6->len, olen);
390 uh6->nextheader = IP_UDPPROTO;
391 uh6->hoplimit = ottl;
394 panic("udpiput: version %d", version);
395 return; /* to avoid a warning */
400 c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
402 /* no conversation found */
403 upriv->ustats.udpNoPorts++;
405 netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
413 icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0);
416 panic("udpiput2: version %d", version);
422 ucb = (Udpcb*)c->ptcl;
424 if(c->state == Announced){
425 if(ucb->headers == 0){
426 /* create a new conversation */
427 if(ipforme(f, laddr) != Runi) {
430 v4tov6(laddr, ifc->lifc->local);
433 ipmove(laddr, ifc->lifc->local);
436 panic("udpiput3: version %d", version);
439 c = Fsnewcall(c, raddr, rport, laddr, lport, version);
445 iphtadd(&upriv->ht, c);
446 ucb = (Udpcb*)c->ptcl;
454 * Trim the packet down to data size
456 len -= UDP_UDPHDR_SZ;
459 bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
462 bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
466 panic("udpiput4: version %d", version);
470 netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
476 netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
479 switch(ucb->headers){
481 /* pass the src address */
482 bp = padblock(bp, UDP_USEAD7);
484 ipmove(p, raddr); p += IPaddrlen;
485 ipmove(p, laddr); p += IPaddrlen;
486 ipmove(p, ifc->lifc->local); p += IPaddrlen;
487 hnputs(p, rport); p += 2;
493 netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
498 bp = concatblock(bp);
506 udpctl(Conv *c, char **f, int n)
510 ucb = (Udpcb*)c->ptcl;
512 if(strcmp(f[0], "hangup") == 0){
517 if(strcmp(f[0], "headers") == 0){
518 ucb->headers = 7; /* new headers format */
522 return "unknown control request";
526 udpadvise(Proto *udp, Block *bp, char *msg)
530 uchar source[IPaddrlen], dest[IPaddrlen];
531 ushort psource, pdest;
535 h4 = (Udp4hdr*)(bp->rp);
536 version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
540 v4tov6(dest, h4->udpdst);
541 v4tov6(source, h4->udpsrc);
542 psource = nhgets(h4->udpsport);
543 pdest = nhgets(h4->udpdport);
546 h6 = (Udp6hdr*)(bp->rp);
547 ipmove(dest, h6->udpdst);
548 ipmove(source, h6->udpsrc);
549 psource = nhgets(h6->udpsport);
550 pdest = nhgets(h6->udpdport);
553 panic("udpadvise: version %d", version);
554 return; /* to avoid a warning */
557 /* Look for a connection */
559 for(p = udp->conv; *p; p++) {
561 if(s->rport == pdest)
562 if(s->lport == psource)
563 if(ipcmp(s->raddr, dest) == 0)
564 if(ipcmp(s->laddr, source) == 0){
581 udpstats(Proto *udp, char *buf, int len)
586 return snprint(buf, len, "InDatagrams: %llud\nNoPorts: %lud\n"
587 "InErrors: %lud\nOutDatagrams: %llud\n",
588 upriv->ustats.udpInDatagrams,
589 upriv->ustats.udpNoPorts,
590 upriv->ustats.udpInErrors,
591 upriv->ustats.udpOutDatagrams);
599 udp = smalloc(sizeof(Proto));
600 udp->priv = smalloc(sizeof(Udppriv));
602 udp->connect = udpconnect;
603 udp->announce = udpannounce;
605 udp->state = udpstate;
606 udp->create = udpcreate;
607 udp->close = udpclose;
609 udp->advise = udpadvise;
610 udp->stats = udpstats;
611 udp->ipproto = IP_UDPPROTO;
613 udp->ptclsize = sizeof(Udpcb);