1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #include "ip.h"
9 #include "ipv6.h"
10
11
12 #define DPRINT if(0)print
13
14 enum
15 {
16 UDP_UDPHDR_SZ = 8,
17
18 UDP4_PHDR_OFF = 8,
19 UDP4_PHDR_SZ = 12,
20 UDP4_IPHDR_SZ = 20,
21 UDP6_IPHDR_SZ = 40,
22 UDP6_PHDR_SZ = 40,
23 UDP6_PHDR_OFF = 0,
24
25 IP_UDPPROTO = 17,
26 UDP_USEAD7 = 52,
27 UDP_USEAD6 = 36,
28
29 Udprxms = 200,
30 Udptickms = 100,
31 Udpmaxxmit = 10,
32 };
33
34 typedef struct Udp4hdr Udp4hdr;
35 struct Udp4hdr
36 {
37 /* ip header */
38 uchar vihl; /* Version and header length */
39 uchar tos; /* Type of service */
40 uchar length[2]; /* packet length */
41 uchar id[2]; /* Identification */
42 uchar frag[2]; /* Fragment information */
43 uchar Unused;
44 uchar udpproto; /* Protocol */
45 uchar udpplen[2]; /* Header plus data length */
46 uchar udpsrc[IPv4addrlen]; /* Ip source */
47 uchar udpdst[IPv4addrlen]; /* Ip destination */
48
49 /* udp header */
50 uchar udpsport[2]; /* Source port */
51 uchar udpdport[2]; /* Destination port */
52 uchar udplen[2]; /* data length */
53 uchar udpcksum[2]; /* Checksum */
54 };
55
56 typedef struct Udp6hdr Udp6hdr;
57 struct Udp6hdr {
58 uchar viclfl[4];
59 uchar len[2];
60 uchar nextheader;
61 uchar hoplimit;
62 uchar udpsrc[IPaddrlen];
63 uchar udpdst[IPaddrlen];
64
65 /* udp header */
66 uchar udpsport[2]; /* Source port */
67 uchar udpdport[2]; /* Destination port */
68 uchar udplen[2]; /* data length */
69 uchar udpcksum[2]; /* Checksum */
70 };
71
72 /* MIB II counters */
73 typedef struct Udpstats Udpstats;
74 struct Udpstats
75 {
76 ulong udpInDatagrams;
77 ulong udpNoPorts;
78 ulong udpInErrors;
79 ulong udpOutDatagrams;
80 };
81
82 typedef struct Udppriv Udppriv;
83 struct Udppriv
84 {
85 Ipht ht;
86
87 /* MIB counters */
88 Udpstats ustats;
89
90 /* non-MIB stats */
91 ulong csumerr; /* checksum errors */
92 ulong lenerr; /* short packet */
93 };
94
95 void (*etherprofiler)(char *name, int qlen);
96 void udpkick(void *x, Block *bp);
97
98 /*
99 * protocol specific part of Conv
100 */
101 typedef struct Udpcb Udpcb;
102 struct Udpcb
103 {
104 QLock;
105 uchar headers;
106 };
107
108 static char*
udpconnect(Conv * c,char ** argv,int argc)109 udpconnect(Conv *c, char **argv, int argc)
110 {
111 char *e;
112 Udppriv *upriv;
113
114 upriv = c->p->priv;
115 e = Fsstdconnect(c, argv, argc);
116 Fsconnected(c, e);
117 if(e != nil)
118 return e;
119
120 iphtadd(&upriv->ht, c);
121 return nil;
122 }
123
124
125 static int
udpstate(Conv * c,char * state,int n)126 udpstate(Conv *c, char *state, int n)
127 {
128 return snprint(state, n, "%s qin %d qout %d",
129 c->inuse ? "Open" : "Closed",
130 c->rq ? qlen(c->rq) : 0,
131 c->wq ? qlen(c->wq) : 0
132 );
133 }
134
135 static char*
udpannounce(Conv * c,char ** argv,int argc)136 udpannounce(Conv *c, char** argv, int argc)
137 {
138 char *e;
139 Udppriv *upriv;
140
141 upriv = c->p->priv;
142 e = Fsstdannounce(c, argv, argc);
143 if(e != nil)
144 return e;
145 Fsconnected(c, nil);
146 iphtadd(&upriv->ht, c);
147
148 return nil;
149 }
150
151 static void
udpcreate(Conv * c)152 udpcreate(Conv *c)
153 {
154 c->rq = qopen(64*1024, Qmsg, 0, 0);
155 c->wq = qbypass(udpkick, c);
156 }
157
158 static void
udpclose(Conv * c)159 udpclose(Conv *c)
160 {
161 Udpcb *ucb;
162 Udppriv *upriv;
163
164 upriv = c->p->priv;
165 iphtrem(&upriv->ht, c);
166
167 c->state = 0;
168 qclose(c->rq);
169 qclose(c->wq);
170 qclose(c->eq);
171 ipmove(c->laddr, IPnoaddr);
172 ipmove(c->raddr, IPnoaddr);
173 c->lport = 0;
174 c->rport = 0;
175
176 ucb = (Udpcb*)c->ptcl;
177 ucb->headers = 0;
178
179 qunlock(c);
180 }
181
182 void
udpkick(void * x,Block * bp)183 udpkick(void *x, Block *bp)
184 {
185 Conv *c = x;
186 Udp4hdr *uh4;
187 Udp6hdr *uh6;
188 ushort rport;
189 uchar laddr[IPaddrlen], raddr[IPaddrlen];
190 Udpcb *ucb;
191 int dlen, ptcllen;
192 Udppriv *upriv;
193 Fs *f;
194 int version;
195 Conv *rc;
196
197 upriv = c->p->priv;
198 f = c->p->f;
199
200 netlog(c->p->f, Logudp, "udp: kick\n");
201 if(bp == nil)
202 return;
203
204 ucb = (Udpcb*)c->ptcl;
205 switch(ucb->headers) {
206 case 7:
207 /* get user specified addresses */
208 bp = pullupblock(bp, UDP_USEAD7);
209 if(bp == nil)
210 return;
211 ipmove(raddr, bp->rp);
212 bp->rp += IPaddrlen;
213 ipmove(laddr, bp->rp);
214 bp->rp += IPaddrlen;
215 /* pick interface closest to dest */
216 if(ipforme(f, laddr) != Runi)
217 findlocalip(f, laddr, raddr);
218 bp->rp += IPaddrlen; /* Ignore ifc address */
219 rport = nhgets(bp->rp);
220 bp->rp += 2+2; /* Ignore local port */
221 break;
222 case 6:
223 /* get user specified addresses */
224 bp = pullupblock(bp, UDP_USEAD6);
225 if(bp == nil)
226 return;
227 ipmove(raddr, bp->rp);
228 bp->rp += IPaddrlen;
229 ipmove(laddr, bp->rp);
230 bp->rp += IPaddrlen;
231 /* pick interface closest to dest */
232 if(ipforme(f, laddr) != Runi)
233 findlocalip(f, laddr, raddr);
234 rport = nhgets(bp->rp);
235 bp->rp += 2+2; /* Ignore local port */
236 break;
237 default:
238 rport = 0;
239 break;
240 }
241
242 if(ucb->headers) {
243 if(memcmp(laddr, v4prefix, IPv4off) == 0 ||
244 ipcmp(laddr, IPnoaddr) == 0)
245 version = V4;
246 else
247 version = V6;
248 } else {
249 if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
250 memcmp(c->laddr, v4prefix, IPv4off) == 0)
251 || ipcmp(c->raddr, IPnoaddr) == 0)
252 version = V4;
253 else
254 version = V6;
255 }
256
257 dlen = blocklen(bp);
258
259 /* fill in pseudo header and compute checksum */
260 switch(version){
261 case V4:
262 bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
263 if(bp == nil)
264 return;
265
266 uh4 = (Udp4hdr *)(bp->rp);
267 ptcllen = dlen + UDP_UDPHDR_SZ;
268 uh4->Unused = 0;
269 uh4->udpproto = IP_UDPPROTO;
270 uh4->frag[0] = 0;
271 uh4->frag[1] = 0;
272 hnputs(uh4->udpplen, ptcllen);
273 if(ucb->headers) {
274 v6tov4(uh4->udpdst, raddr);
275 hnputs(uh4->udpdport, rport);
276 v6tov4(uh4->udpsrc, laddr);
277 rc = nil;
278 } else {
279 v6tov4(uh4->udpdst, c->raddr);
280 hnputs(uh4->udpdport, c->rport);
281 if(ipcmp(c->laddr, IPnoaddr) == 0)
282 findlocalip(f, c->laddr, c->raddr);
283 v6tov4(uh4->udpsrc, c->laddr);
284 rc = c;
285 }
286 hnputs(uh4->udpsport, c->lport);
287 hnputs(uh4->udplen, ptcllen);
288 uh4->udpcksum[0] = 0;
289 uh4->udpcksum[1] = 0;
290 hnputs(uh4->udpcksum,
291 ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
292 uh4->vihl = IP_VER4;
293 ipoput4(f, bp, 0, c->ttl, c->tos, rc);
294 break;
295
296 case V6:
297 bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
298 if(bp == nil)
299 return;
300
301 // using the v6 ip header to create pseudo header
302 // first then reset it to the normal ip header
303 uh6 = (Udp6hdr *)(bp->rp);
304 memset(uh6, 0, 8);
305 ptcllen = dlen + UDP_UDPHDR_SZ;
306 hnputl(uh6->viclfl, ptcllen);
307 uh6->hoplimit = IP_UDPPROTO;
308 if(ucb->headers) {
309 ipmove(uh6->udpdst, raddr);
310 hnputs(uh6->udpdport, rport);
311 ipmove(uh6->udpsrc, laddr);
312 rc = nil;
313 } else {
314 ipmove(uh6->udpdst, c->raddr);
315 hnputs(uh6->udpdport, c->rport);
316 if(ipcmp(c->laddr, IPnoaddr) == 0)
317 findlocalip(f, c->laddr, c->raddr);
318 ipmove(uh6->udpsrc, c->laddr);
319 rc = c;
320 }
321 hnputs(uh6->udpsport, c->lport);
322 hnputs(uh6->udplen, ptcllen);
323 uh6->udpcksum[0] = 0;
324 uh6->udpcksum[1] = 0;
325 hnputs(uh6->udpcksum,
326 ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
327 memset(uh6, 0, 8);
328 uh6->viclfl[0] = IP_VER6;
329 hnputs(uh6->len, ptcllen);
330 uh6->nextheader = IP_UDPPROTO;
331 ipoput6(f, bp, 0, c->ttl, c->tos, rc);
332 break;
333
334 default:
335 panic("udpkick: version %d", version);
336 }
337 upriv->ustats.udpOutDatagrams++;
338 }
339
340 void
udpiput(Proto * udp,Ipifc * ifc,Block * bp)341 udpiput(Proto *udp, Ipifc *ifc, Block *bp)
342 {
343 int len;
344 Udp4hdr *uh4;
345 Udp6hdr *uh6;
346 Conv *c;
347 Udpcb *ucb;
348 uchar raddr[IPaddrlen], laddr[IPaddrlen];
349 ushort rport, lport;
350 Udppriv *upriv;
351 Fs *f;
352 int version;
353 int ottl, oviclfl, olen;
354 uchar *p;
355
356 upriv = udp->priv;
357 f = udp->f;
358 upriv->ustats.udpInDatagrams++;
359
360 uh4 = (Udp4hdr*)(bp->rp);
361 version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4;
362
363 /*
364 * Put back pseudo header for checksum
365 * (remember old values for icmpnoconv())
366 */
367 switch(version) {
368 case V4:
369 ottl = uh4->Unused;
370 uh4->Unused = 0;
371 len = nhgets(uh4->udplen);
372 olen = nhgets(uh4->udpplen);
373 hnputs(uh4->udpplen, len);
374
375 v4tov6(raddr, uh4->udpsrc);
376 v4tov6(laddr, uh4->udpdst);
377 lport = nhgets(uh4->udpdport);
378 rport = nhgets(uh4->udpsport);
379
380 if(nhgets(uh4->udpcksum)) {
381 if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
382 upriv->ustats.udpInErrors++;
383 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
384 DPRINT("udp: checksum error %I\n", raddr);
385 freeblist(bp);
386 return;
387 }
388 }
389 uh4->Unused = ottl;
390 hnputs(uh4->udpplen, olen);
391 break;
392 case V6:
393 uh6 = (Udp6hdr*)(bp->rp);
394 len = nhgets(uh6->udplen);
395 oviclfl = nhgetl(uh6->viclfl);
396 olen = nhgets(uh6->len);
397 ottl = uh6->hoplimit;
398 ipmove(raddr, uh6->udpsrc);
399 ipmove(laddr, uh6->udpdst);
400 lport = nhgets(uh6->udpdport);
401 rport = nhgets(uh6->udpsport);
402 memset(uh6, 0, 8);
403 hnputl(uh6->viclfl, len);
404 uh6->hoplimit = IP_UDPPROTO;
405 if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
406 upriv->ustats.udpInErrors++;
407 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
408 DPRINT("udp: checksum error %I\n", raddr);
409 freeblist(bp);
410 return;
411 }
412 hnputl(uh6->viclfl, oviclfl);
413 hnputs(uh6->len, olen);
414 uh6->nextheader = IP_UDPPROTO;
415 uh6->hoplimit = ottl;
416 break;
417 default:
418 panic("udpiput: version %d", version);
419 return; /* to avoid a warning */
420 }
421
422 qlock(udp);
423
424 c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
425 if(c == nil){
426 /* no converstation found */
427 upriv->ustats.udpNoPorts++;
428 qunlock(udp);
429 netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
430 laddr, lport);
431
432 switch(version){
433 case V4:
434 icmpnoconv(f, bp);
435 break;
436 case V6:
437 icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
438 break;
439 default:
440 panic("udpiput2: version %d", version);
441 }
442
443 freeblist(bp);
444 return;
445 }
446 ucb = (Udpcb*)c->ptcl;
447
448 if(c->state == Announced){
449 if(ucb->headers == 0){
450 /* create a new conversation */
451 if(ipforme(f, laddr) != Runi) {
452 switch(version){
453 case V4:
454 v4tov6(laddr, ifc->lifc->local);
455 break;
456 case V6:
457 ipmove(laddr, ifc->lifc->local);
458 break;
459 default:
460 panic("udpiput3: version %d", version);
461 }
462 }
463 c = Fsnewcall(c, raddr, rport, laddr, lport, version);
464 if(c == nil){
465 qunlock(udp);
466 freeblist(bp);
467 return;
468 }
469 iphtadd(&upriv->ht, c);
470 ucb = (Udpcb*)c->ptcl;
471 }
472 }
473
474 qlock(c);
475 qunlock(udp);
476
477 /*
478 * Trim the packet down to data size
479 */
480 len -= UDP_UDPHDR_SZ;
481 switch(version){
482 case V4:
483 bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
484 break;
485 case V6:
486 bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
487 break;
488 default:
489 bp = nil;
490 panic("udpiput4: version %d", version);
491 }
492 if(bp == nil){
493 qunlock(c);
494 netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
495 laddr, lport);
496 upriv->lenerr++;
497 return;
498 }
499
500 netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
501 laddr, lport, len);
502
503 switch(ucb->headers){
504 case 7:
505 /* pass the src address */
506 bp = padblock(bp, UDP_USEAD7);
507 p = bp->rp;
508 ipmove(p, raddr); p += IPaddrlen;
509 ipmove(p, laddr); p += IPaddrlen;
510 ipmove(p, ifc->lifc->local); p += IPaddrlen;
511 hnputs(p, rport); p += 2;
512 hnputs(p, lport);
513 break;
514 case 6:
515 /* pass the src address */
516 bp = padblock(bp, UDP_USEAD6);
517 p = bp->rp;
518 ipmove(p, raddr); p += IPaddrlen;
519 ipmove(p, ipforme(f, laddr)==Runi ? laddr : ifc->lifc->local); p += IPaddrlen;
520 hnputs(p, rport); p += 2;
521 hnputs(p, lport);
522 break;
523 }
524
525 if(bp->next)
526 bp = concatblock(bp);
527
528 if(qfull(c->rq)){
529 qunlock(c);
530 netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
531 laddr, lport);
532 freeblist(bp);
533 return;
534 }
535
536 qpass(c->rq, bp);
537 qunlock(c);
538
539 }
540
541 char*
udpctl(Conv * c,char ** f,int n)542 udpctl(Conv *c, char **f, int n)
543 {
544 Udpcb *ucb;
545
546 ucb = (Udpcb*)c->ptcl;
547 if(n == 1){
548 if(strcmp(f[0], "oldheaders") == 0){
549 ucb->headers = 6;
550 return nil;
551 } else if(strcmp(f[0], "headers") == 0){
552 ucb->headers = 7;
553 return nil;
554 }
555 }
556 return "unknown control request";
557 }
558
559 void
udpadvise(Proto * udp,Block * bp,char * msg)560 udpadvise(Proto *udp, Block *bp, char *msg)
561 {
562 Udp4hdr *h4;
563 Udp6hdr *h6;
564 uchar source[IPaddrlen], dest[IPaddrlen];
565 ushort psource, pdest;
566 Conv *s, **p;
567 int version;
568
569 h4 = (Udp4hdr*)(bp->rp);
570 version = ((h4->vihl&0xF0)==IP_VER6) ? V6 : V4;
571
572 switch(version) {
573 case V4:
574 v4tov6(dest, h4->udpdst);
575 v4tov6(source, h4->udpsrc);
576 psource = nhgets(h4->udpsport);
577 pdest = nhgets(h4->udpdport);
578 break;
579 case V6:
580 h6 = (Udp6hdr*)(bp->rp);
581 ipmove(dest, h6->udpdst);
582 ipmove(source, h6->udpsrc);
583 psource = nhgets(h6->udpsport);
584 pdest = nhgets(h6->udpdport);
585 break;
586 default:
587 panic("udpadvise: version %d", version);
588 return; /* to avoid a warning */
589 }
590
591 /* Look for a connection */
592 qlock(udp);
593 for(p = udp->conv; *p; p++) {
594 s = *p;
595 if(s->rport == pdest)
596 if(s->lport == psource)
597 if(ipcmp(s->raddr, dest) == 0)
598 if(ipcmp(s->laddr, source) == 0){
599 if(s->ignoreadvice)
600 break;
601 qlock(s);
602 qunlock(udp);
603 qhangup(s->rq, msg);
604 qhangup(s->wq, msg);
605 qunlock(s);
606 freeblist(bp);
607 return;
608 }
609 }
610 qunlock(udp);
611 freeblist(bp);
612 }
613
614 int
udpstats(Proto * udp,char * buf,int len)615 udpstats(Proto *udp, char *buf, int len)
616 {
617 Udppriv *upriv;
618
619 upriv = udp->priv;
620 return snprint(buf, len, "InDatagrams: %lud\nNoPorts: %lud\nInErrors: %lud\nOutDatagrams: %lud\n",
621 upriv->ustats.udpInDatagrams,
622 upriv->ustats.udpNoPorts,
623 upriv->ustats.udpInErrors,
624 upriv->ustats.udpOutDatagrams);
625 }
626
627 void
udpinit(Fs * fs)628 udpinit(Fs *fs)
629 {
630 Proto *udp;
631
632 udp = smalloc(sizeof(Proto));
633 udp->priv = smalloc(sizeof(Udppriv));
634 udp->name = "udp";
635 udp->connect = udpconnect;
636 udp->announce = udpannounce;
637 udp->ctl = udpctl;
638 udp->state = udpstate;
639 udp->create = udpcreate;
640 udp->close = udpclose;
641 udp->rcv = udpiput;
642 udp->advise = udpadvise;
643 udp->stats = udpstats;
644 udp->ipproto = IP_UDPPROTO;
645 udp->nc = Nchans;
646 udp->ptclsize = sizeof(Udpcb);
647
648 Fsproto(fs, udp);
649 }
650