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* 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 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* 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 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 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 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 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* 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 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 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 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