udp.c 13 KB

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