ip.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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. #define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0)
  9. static char *statnames[] =
  10. {
  11. [Forwarding] "Forwarding",
  12. [DefaultTTL] "DefaultTTL",
  13. [InReceives] "InReceives",
  14. [InHdrErrors] "InHdrErrors",
  15. [InAddrErrors] "InAddrErrors",
  16. [ForwDatagrams] "ForwDatagrams",
  17. [InUnknownProtos] "InUnknownProtos",
  18. [InDiscards] "InDiscards",
  19. [InDelivers] "InDelivers",
  20. [OutRequests] "OutRequests",
  21. [OutDiscards] "OutDiscards",
  22. [OutNoRoutes] "OutNoRoutes",
  23. [ReasmTimeout] "ReasmTimeout",
  24. [ReasmReqds] "ReasmReqds",
  25. [ReasmOKs] "ReasmOKs",
  26. [ReasmFails] "ReasmFails",
  27. [FragOKs] "FragOKs",
  28. [FragFails] "FragFails",
  29. [FragCreates] "FragCreates",
  30. };
  31. #define BLKIP(xp) ((Ip4hdr*)((xp)->rp))
  32. /*
  33. * This sleazy macro relies on the media header size being
  34. * larger than sizeof(Ipfrag). ipreassemble checks this is true
  35. */
  36. #define BKFG(xp) ((Ipfrag*)((xp)->base))
  37. ushort ipcsum(uchar*);
  38. Block* ip4reassemble(IP*, int, Block*, Ip4hdr*);
  39. void ipfragfree4(IP*, Fragment4*);
  40. Fragment4* ipfragallo4(IP*);
  41. void
  42. ip_init_6(Fs *f)
  43. {
  44. v6params *v6p;
  45. v6p = smalloc(sizeof(v6params));
  46. v6p->rp.mflag = 0; /* default not managed */
  47. v6p->rp.oflag = 0;
  48. v6p->rp.maxraint = 600000; /* millisecs */
  49. v6p->rp.minraint = 200000;
  50. v6p->rp.linkmtu = 0; /* no mtu sent */
  51. v6p->rp.reachtime = 0;
  52. v6p->rp.rxmitra = 0;
  53. v6p->rp.ttl = MAXTTL;
  54. v6p->rp.routerlt = 3 * v6p->rp.maxraint;
  55. v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */
  56. v6p->cdrouter = -1;
  57. f->v6p = v6p;
  58. }
  59. void
  60. initfrag(IP *ip, int size)
  61. {
  62. Fragment4 *fq4, *eq4;
  63. Fragment6 *fq6, *eq6;
  64. ip->fragfree4 = (Fragment4*)malloc(sizeof(Fragment4) * size);
  65. if(ip->fragfree4 == nil)
  66. panic("initfrag");
  67. eq4 = &ip->fragfree4[size];
  68. for(fq4 = ip->fragfree4; fq4 < eq4; fq4++)
  69. fq4->next = fq4+1;
  70. ip->fragfree4[size-1].next = nil;
  71. ip->fragfree6 = (Fragment6*)malloc(sizeof(Fragment6) * size);
  72. if(ip->fragfree6 == nil)
  73. panic("initfrag");
  74. eq6 = &ip->fragfree6[size];
  75. for(fq6 = ip->fragfree6; fq6 < eq6; fq6++)
  76. fq6->next = fq6+1;
  77. ip->fragfree6[size-1].next = nil;
  78. }
  79. void
  80. ip_init(Fs *f)
  81. {
  82. IP *ip;
  83. ip = smalloc(sizeof(IP));
  84. initfrag(ip, 100);
  85. f->ip = ip;
  86. ip_init_6(f);
  87. }
  88. void
  89. iprouting(Fs *f, int on)
  90. {
  91. f->ip->iprouting = on;
  92. if(f->ip->iprouting==0)
  93. f->ip->stats[Forwarding] = 2;
  94. else
  95. f->ip->stats[Forwarding] = 1;
  96. }
  97. int
  98. ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
  99. {
  100. Ipifc *ifc;
  101. uchar *gate;
  102. ulong fragoff;
  103. Block *xp, *nb;
  104. Ip4hdr *eh, *feh;
  105. int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
  106. Route *r, *sr;
  107. IP *ip;
  108. int rv = 0;
  109. ip = f->ip;
  110. /* Fill out the ip header */
  111. eh = (Ip4hdr*)(bp->rp);
  112. ip->stats[OutRequests]++;
  113. /* Number of uchars in data and ip header to write */
  114. len = blocklen(bp);
  115. if(gating){
  116. chunk = nhgets(eh->length);
  117. if(chunk > len){
  118. ip->stats[OutDiscards]++;
  119. netlog(f, Logip, "short gated packet\n");
  120. goto free;
  121. }
  122. if(chunk < len)
  123. len = chunk;
  124. }
  125. if(len >= IP_MAX){
  126. ip->stats[OutDiscards]++;
  127. netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
  128. goto free;
  129. }
  130. r = v4lookup(f, eh->dst, c);
  131. if(r == nil){
  132. ip->stats[OutNoRoutes]++;
  133. netlog(f, Logip, "no interface %V\n", eh->dst);
  134. rv = -1;
  135. goto free;
  136. }
  137. ifc = r->ifc;
  138. if(r->type & (Rifc|Runi))
  139. gate = eh->dst;
  140. else
  141. if(r->type & (Rbcast|Rmulti)) {
  142. gate = eh->dst;
  143. sr = v4lookup(f, eh->src, nil);
  144. if(sr != nil && (sr->type & Runi))
  145. ifc = sr->ifc;
  146. }
  147. else
  148. gate = r->v4.gate;
  149. if(!gating)
  150. eh->vihl = IP_VER4|IP_HLEN4;
  151. eh->ttl = ttl;
  152. if(!gating)
  153. eh->tos = tos;
  154. if(!canrlock(ifc))
  155. goto free;
  156. if(waserror()){
  157. runlock(ifc);
  158. nexterror();
  159. }
  160. if(ifc->m == nil)
  161. goto raise;
  162. /* If we dont need to fragment just send it */
  163. if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
  164. medialen = c->maxfragsize - ifc->m->hsize;
  165. else
  166. medialen = ifc->maxtu - ifc->m->hsize;
  167. if(len <= medialen) {
  168. if(!gating)
  169. hnputs(eh->id, incref(&ip->id4));
  170. hnputs(eh->length, len);
  171. if(!gating){
  172. eh->frag[0] = 0;
  173. eh->frag[1] = 0;
  174. }
  175. eh->cksum[0] = 0;
  176. eh->cksum[1] = 0;
  177. hnputs(eh->cksum, ipcsum(&eh->vihl));
  178. assert(bp->next == nil);
  179. ifc->m->bwrite(ifc, bp, V4, gate);
  180. runlock(ifc);
  181. poperror();
  182. return 0;
  183. }
  184. if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst);
  185. if(eh->frag[0] & (IP_DF>>8)){
  186. ip->stats[FragFails]++;
  187. ip->stats[OutDiscards]++;
  188. icmpcantfrag(f, bp, medialen);
  189. netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
  190. goto raise;
  191. }
  192. seglen = (medialen - IP4HDR) & ~7;
  193. if(seglen < 8){
  194. ip->stats[FragFails]++;
  195. ip->stats[OutDiscards]++;
  196. netlog(f, Logip, "%V seglen < 8\n", eh->dst);
  197. goto raise;
  198. }
  199. dlen = len - IP4HDR;
  200. xp = bp;
  201. if(gating)
  202. lid = nhgets(eh->id);
  203. else
  204. lid = incref(&ip->id4);
  205. offset = IP4HDR;
  206. while(xp != nil && offset && offset >= BLEN(xp)) {
  207. offset -= BLEN(xp);
  208. xp = xp->next;
  209. }
  210. xp->rp += offset;
  211. if(gating)
  212. fragoff = nhgets(eh->frag)<<3;
  213. else
  214. fragoff = 0;
  215. dlen += fragoff;
  216. for(; fragoff < dlen; fragoff += seglen) {
  217. nb = allocb(IP4HDR+seglen);
  218. feh = (Ip4hdr*)(nb->rp);
  219. memmove(nb->wp, eh, IP4HDR);
  220. nb->wp += IP4HDR;
  221. if((fragoff + seglen) >= dlen) {
  222. seglen = dlen - fragoff;
  223. hnputs(feh->frag, fragoff>>3);
  224. }
  225. else
  226. hnputs(feh->frag, (fragoff>>3)|IP_MF);
  227. hnputs(feh->length, seglen + IP4HDR);
  228. hnputs(feh->id, lid);
  229. /* Copy up the data area */
  230. chunk = seglen;
  231. while(chunk) {
  232. if(!xp) {
  233. ip->stats[OutDiscards]++;
  234. ip->stats[FragFails]++;
  235. freeblist(nb);
  236. netlog(f, Logip, "!xp: chunk %d\n", chunk);
  237. goto raise;
  238. }
  239. blklen = chunk;
  240. if(BLEN(xp) < chunk)
  241. blklen = BLEN(xp);
  242. memmove(nb->wp, xp->rp, blklen);
  243. nb->wp += blklen;
  244. xp->rp += blklen;
  245. chunk -= blklen;
  246. if(xp->rp == xp->wp)
  247. xp = xp->next;
  248. }
  249. feh->cksum[0] = 0;
  250. feh->cksum[1] = 0;
  251. hnputs(feh->cksum, ipcsum(&feh->vihl));
  252. ifc->m->bwrite(ifc, nb, V4, gate);
  253. ip->stats[FragCreates]++;
  254. }
  255. ip->stats[FragOKs]++;
  256. raise:
  257. runlock(ifc);
  258. poperror();
  259. free:
  260. freeblist(bp);
  261. return rv;
  262. }
  263. void
  264. ipiput4(Fs *f, Ipifc *ifc, Block *bp)
  265. {
  266. int hl;
  267. int hop, tos, proto, olen;
  268. Ip4hdr *h;
  269. Proto *p;
  270. ushort frag;
  271. int notforme;
  272. uchar *dp, v6dst[IPaddrlen];
  273. IP *ip;
  274. Route *r;
  275. Conv conv;
  276. if(BLKIPVER(bp) != IP_VER4) {
  277. ipiput6(f, ifc, bp);
  278. return;
  279. }
  280. ip = f->ip;
  281. ip->stats[InReceives]++;
  282. /*
  283. * Ensure we have all the header info in the first
  284. * block. Make life easier for other protocols by
  285. * collecting up to the first 64 bytes in the first block.
  286. */
  287. if(BLEN(bp) < 64) {
  288. hl = blocklen(bp);
  289. if(hl < IP4HDR)
  290. hl = IP4HDR;
  291. if(hl > 64)
  292. hl = 64;
  293. bp = pullupblock(bp, hl);
  294. if(bp == nil)
  295. return;
  296. }
  297. h = (Ip4hdr*)(bp->rp);
  298. /* dump anything that whose header doesn't checksum */
  299. if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
  300. ip->stats[InHdrErrors]++;
  301. netlog(f, Logip, "ip: checksum error %V\n", h->src);
  302. freeblist(bp);
  303. return;
  304. }
  305. v4tov6(v6dst, h->dst);
  306. notforme = ipforme(f, v6dst) == 0;
  307. /* Check header length and version */
  308. if((h->vihl&0x0F) != IP_HLEN4) {
  309. hl = (h->vihl&0xF)<<2;
  310. if(hl < (IP_HLEN4<<2)) {
  311. ip->stats[InHdrErrors]++;
  312. netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
  313. freeblist(bp);
  314. return;
  315. }
  316. /* If this is not routed strip off the options */
  317. if(notforme == 0) {
  318. olen = nhgets(h->length);
  319. dp = bp->rp + (hl - (IP_HLEN4<<2));
  320. memmove(dp, h, IP_HLEN4<<2);
  321. bp->rp = dp;
  322. h = (Ip4hdr*)(bp->rp);
  323. h->vihl = (IP_VER4|IP_HLEN4);
  324. hnputs(h->length, olen-hl+(IP_HLEN4<<2));
  325. }
  326. }
  327. /* route */
  328. if(notforme) {
  329. if(!ip->iprouting){
  330. freeblist(bp);
  331. return;
  332. }
  333. /* don't forward to source's network */
  334. conv.r = nil;
  335. r = v4lookup(f, h->dst, &conv);
  336. if(r == nil || r->ifc == ifc){
  337. ip->stats[OutDiscards]++;
  338. freeblist(bp);
  339. return;
  340. }
  341. /* don't forward if packet has timed out */
  342. hop = h->ttl;
  343. if(hop < 1) {
  344. ip->stats[InHdrErrors]++;
  345. icmpttlexceeded(f, ifc->lifc->local, bp);
  346. freeblist(bp);
  347. return;
  348. }
  349. /* reassemble if the interface expects it */
  350. if(r->ifc == nil) panic("nil route rfc");
  351. if(r->ifc->reassemble){
  352. frag = nhgets(h->frag);
  353. if(frag) {
  354. h->tos = 0;
  355. if(frag & IP_MF)
  356. h->tos = 1;
  357. bp = ip4reassemble(ip, frag, bp, h);
  358. if(bp == nil)
  359. return;
  360. h = (Ip4hdr*)(bp->rp);
  361. }
  362. }
  363. ip->stats[ForwDatagrams]++;
  364. tos = h->tos;
  365. hop = h->ttl;
  366. ipoput4(f, bp, 1, hop - 1, tos, &conv);
  367. return;
  368. }
  369. frag = nhgets(h->frag);
  370. if(frag) {
  371. h->tos = 0;
  372. if(frag & IP_MF)
  373. h->tos = 1;
  374. bp = ip4reassemble(ip, frag, bp, h);
  375. if(bp == nil)
  376. return;
  377. h = (Ip4hdr*)(bp->rp);
  378. }
  379. /* don't let any frag info go up the stack */
  380. h->frag[0] = 0;
  381. h->frag[1] = 0;
  382. proto = h->proto;
  383. p = Fsrcvpcol(f, proto);
  384. if(p != nil && p->rcv != nil) {
  385. ip->stats[InDelivers]++;
  386. (*p->rcv)(p, ifc, bp);
  387. return;
  388. }
  389. ip->stats[InDiscards]++;
  390. ip->stats[InUnknownProtos]++;
  391. freeblist(bp);
  392. }
  393. int
  394. ipstats(Fs *f, char *buf, int len)
  395. {
  396. IP *ip;
  397. char *p, *e;
  398. int i;
  399. ip = f->ip;
  400. ip->stats[DefaultTTL] = MAXTTL;
  401. p = buf;
  402. e = p+len;
  403. for(i = 0; i < Nipstats; i++)
  404. p = seprint(p, e, "%s: %llud\n", statnames[i], ip->stats[i]);
  405. return p - buf;
  406. }
  407. Block*
  408. ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
  409. {
  410. int fend;
  411. ushort id;
  412. Fragment4 *f, *fnext;
  413. ulong src, dst;
  414. Block *bl, **l, *last, *prev;
  415. int ovlap, len, fragsize, pktposn;
  416. src = nhgetl(ih->src);
  417. dst = nhgetl(ih->dst);
  418. id = nhgets(ih->id);
  419. /*
  420. * block lists are too hard, pullupblock into a single block
  421. */
  422. if(bp->next){
  423. bp = pullupblock(bp, blocklen(bp));
  424. ih = (Ip4hdr*)(bp->rp);
  425. }
  426. qlock(&ip->fraglock4);
  427. /*
  428. * find a reassembly queue for this fragment
  429. */
  430. for(f = ip->flisthead4; f; f = fnext){
  431. fnext = f->next; /* because ipfragfree4 changes the list */
  432. if(f->src == src && f->dst == dst && f->id == id)
  433. break;
  434. if(f->age < NOW){
  435. ip->stats[ReasmTimeout]++;
  436. ipfragfree4(ip, f);
  437. }
  438. }
  439. /*
  440. * if this isn't a fragmented packet, accept it
  441. * and get rid of any fragments that might go
  442. * with it.
  443. */
  444. if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
  445. if(f != nil) {
  446. ipfragfree4(ip, f);
  447. ip->stats[ReasmFails]++;
  448. }
  449. qunlock(&ip->fraglock4);
  450. return bp;
  451. }
  452. if(bp->base+IPFRAGSZ >= bp->rp){
  453. bp = padblock(bp, IPFRAGSZ);
  454. bp->rp += IPFRAGSZ;
  455. }
  456. BKFG(bp)->foff = offset<<3;
  457. BKFG(bp)->flen = nhgets(ih->length)-IP4HDR;
  458. /* First fragment allocates a reassembly queue */
  459. if(f == nil) {
  460. f = ipfragallo4(ip);
  461. f->id = id;
  462. f->src = src;
  463. f->dst = dst;
  464. f->blist = bp;
  465. qunlock(&ip->fraglock4);
  466. ip->stats[ReasmReqds]++;
  467. return nil;
  468. }
  469. /*
  470. * find the new fragment's position in the queue
  471. */
  472. prev = nil;
  473. l = &f->blist;
  474. bl = f->blist;
  475. while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) {
  476. prev = bl;
  477. l = &bl->next;
  478. bl = bl->next;
  479. }
  480. /* Check overlap of a previous fragment - trim away as necessary */
  481. if(prev) {
  482. ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
  483. if(ovlap > 0) {
  484. if(ovlap >= BKFG(bp)->flen) {
  485. freeblist(bp);
  486. qunlock(&ip->fraglock4);
  487. return nil;
  488. }
  489. BKFG(prev)->flen -= ovlap;
  490. }
  491. }
  492. /* Link onto assembly queue */
  493. bp->next = *l;
  494. *l = bp;
  495. /* Check to see if succeeding segments overlap */
  496. if(bp->next) {
  497. l = &bp->next;
  498. fend = BKFG(bp)->foff + BKFG(bp)->flen;
  499. /* Take completely covered segments out */
  500. while(*l) {
  501. ovlap = fend - BKFG(*l)->foff;
  502. if(ovlap <= 0)
  503. break;
  504. if(ovlap < BKFG(*l)->flen) {
  505. BKFG(*l)->flen -= ovlap;
  506. BKFG(*l)->foff += ovlap;
  507. /* move up ih hdrs */
  508. memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
  509. (*l)->rp += ovlap;
  510. break;
  511. }
  512. last = (*l)->next;
  513. (*l)->next = nil;
  514. freeblist(*l);
  515. *l = last;
  516. }
  517. }
  518. /*
  519. * look for a complete packet. if we get to a fragment
  520. * without IP_MF set, we're done.
  521. */
  522. pktposn = 0;
  523. for(bl = f->blist; bl; bl = bl->next) {
  524. if(BKFG(bl)->foff != pktposn)
  525. break;
  526. if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) {
  527. bl = f->blist;
  528. len = nhgets(BLKIP(bl)->length);
  529. bl->wp = bl->rp + len;
  530. /* Pullup all the fragment headers and
  531. * return a complete packet
  532. */
  533. for(bl = bl->next; bl; bl = bl->next) {
  534. fragsize = BKFG(bl)->flen;
  535. len += fragsize;
  536. bl->rp += IP4HDR;
  537. bl->wp = bl->rp + fragsize;
  538. }
  539. bl = f->blist;
  540. f->blist = nil;
  541. ipfragfree4(ip, f);
  542. ih = BLKIP(bl);
  543. hnputs(ih->length, len);
  544. qunlock(&ip->fraglock4);
  545. ip->stats[ReasmOKs]++;
  546. return bl;
  547. }
  548. pktposn += BKFG(bl)->flen;
  549. }
  550. qunlock(&ip->fraglock4);
  551. return nil;
  552. }
  553. /*
  554. * ipfragfree4 - Free a list of fragments - assume hold fraglock4
  555. */
  556. void
  557. ipfragfree4(IP *ip, Fragment4 *frag)
  558. {
  559. Fragment4 *fl, **l;
  560. if(frag->blist)
  561. freeblist(frag->blist);
  562. frag->src = 0;
  563. frag->id = 0;
  564. frag->blist = nil;
  565. l = &ip->flisthead4;
  566. for(fl = *l; fl; fl = fl->next) {
  567. if(fl == frag) {
  568. *l = frag->next;
  569. break;
  570. }
  571. l = &fl->next;
  572. }
  573. frag->next = ip->fragfree4;
  574. ip->fragfree4 = frag;
  575. }
  576. /*
  577. * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
  578. */
  579. Fragment4 *
  580. ipfragallo4(IP *ip)
  581. {
  582. Fragment4 *f;
  583. while(ip->fragfree4 == nil) {
  584. /* free last entry on fraglist */
  585. for(f = ip->flisthead4; f->next; f = f->next)
  586. ;
  587. ipfragfree4(ip, f);
  588. }
  589. f = ip->fragfree4;
  590. ip->fragfree4 = f->next;
  591. f->next = ip->flisthead4;
  592. ip->flisthead4 = f;
  593. f->age = NOW + 30000;
  594. return f;
  595. }
  596. ushort
  597. ipcsum(uchar *addr)
  598. {
  599. int len;
  600. ulong sum;
  601. sum = 0;
  602. len = (addr[0]&0xf)<<2;
  603. while(len > 0) {
  604. sum += addr[0]<<8 | addr[1] ;
  605. len -= 2;
  606. addr += 2;
  607. }
  608. sum = (sum & 0xffff) + (sum >> 16);
  609. sum = (sum & 0xffff) + (sum >> 16);
  610. return (sum^0xffff);
  611. }