udp.c 12 KB

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