udp.c 13 KB

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