ip.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:15k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. #undef SIM
  2. /* Upper half of IP, consisting of send/receive primitives, including
  3.  * fragment reassembly, for higher level protocols.
  4.  * Not needed when running as a standalone gateway.
  5.  * Copyright 1991 Phil Karn, KA9Q
  6.  */
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "internet.h"
  11. #include "netuser.h"
  12. #include "iface.h"
  13. #include "pktdrvr.h"
  14. #include "ip.h"
  15. #include "icmp.h"
  16. static int fraghandle(struct ip *ip,struct mbuf **bpp);
  17. static void ip_timeout(void *arg);
  18. static void free_reasm(struct reasm *rp);
  19. static void freefrag(struct frag *fp);
  20. static struct reasm *lookup_reasm(struct ip *ip);
  21. static struct reasm *creat_reasm(struct ip *ip);
  22. static struct frag *newfrag(uint16 offset,uint16 last,struct mbuf **bpp);
  23. void ttldec(struct iface *ifp);
  24. struct mib_entry Ip_mib[20] = {
  25. "", 0,
  26. "ipForwarding", 1,
  27. "ipDefaultTTL", MAXTTL,
  28. "ipInReceives", 0,
  29. "ipInHdrErrors", 0,
  30. "ipInAddrErrors", 0,
  31. "ipForwDatagrams", 0,
  32. "ipInUnknownProtos", 0,
  33. "ipInDiscards", 0,
  34. "ipInDelivers", 0,
  35. "ipOutRequests", 0,
  36. "ipOutDiscards", 0,
  37. "ipOutNoRoutes", 0,
  38. "ipReasmTimeout", TLB,
  39. "ipReasmReqds", 0,
  40. "ipReasmOKs", 0,
  41. "ipReasmFails", 0,
  42. "ipFragOKs", 0,
  43. "ipFragFails", 0,
  44. "ipFragCreates", 0,
  45. };
  46. struct reasm *Reasmq;
  47. uint16 Id_cntr = 0; /* Datagram serial number */
  48. static struct raw_ip *Raw_ip;
  49. int Ip_trace = 0;
  50. #define INSERT 0
  51. #define APPEND 1
  52. #define PREPEND 2
  53. /* Send an IP datagram. Modeled after the example interface on p 32 of
  54.  * RFC 791
  55.  */
  56. int
  57. ip_send(
  58. int32 source, /* source address */
  59. int32 dest, /* Destination address */
  60. char protocol, /* Protocol */
  61. char tos, /* Type of service */
  62. char ttl, /* Time-to-live */
  63. struct mbuf **bpp, /* Data portion of datagram */
  64. uint16 length, /* Optional length of data portion */
  65. uint16 id, /* Optional identification */
  66. char df /* Don't-fragment flag */
  67. ){
  68. struct ip ip; /* IP header */
  69. ipOutRequests++;
  70. if(bpp == NULL)
  71. return -1;
  72. if(source == INADDR_ANY)
  73. source = locaddr(dest);
  74. if(length == 0 && *bpp != NULL)
  75. length = len_p(*bpp);
  76. if(id == 0)
  77. id = Id_cntr++;
  78. if(ttl == 0)
  79. ttl = ipDefaultTTL;
  80. /* Fill in IP header */
  81. ip.version = IPVERSION;
  82. ip.tos = tos;
  83. ip.length = IPLEN + length;
  84. ip.id = id;
  85. ip.offset = 0;
  86. ip.flags.mf = 0;
  87. ip.flags.df = df;
  88. ip.flags.congest = 0;
  89. ip.ttl = ttl;
  90. ip.protocol = protocol;
  91. ip.source = source;
  92. ip.dest = dest;
  93. ip.optlen = 0;
  94. if(Ip_trace)
  95. dumpip(NULL,&ip,*bpp,0);
  96. htonip(&ip,bpp,IP_CS_NEW);
  97. if(ismyaddr(ip.dest)){
  98. /* Pretend it has been sent by the loopback interface before
  99.  * it appears in the receive queue
  100.  */
  101. #ifdef SIM
  102. net_sim(bpp);
  103. #else
  104. net_route(&Loopback,bpp);
  105. #endif
  106. Loopback.ipsndcnt++;
  107. Loopback.rawsndcnt++;
  108. Loopback.lastsent = secclock();
  109. } else
  110. net_route(NULL,bpp);
  111. return 0;
  112. }
  113. /* Reassemble incoming IP fragments and dispatch completed datagrams
  114.  * to the proper transport module
  115.  */
  116. void
  117. ip_recv(
  118. struct iface *iface, /* Incoming interface */
  119. struct ip *ip, /* Extracted IP header */
  120. struct mbuf **bpp, /* Data portion */
  121. int rxbroadcast, /* True if received on subnet broadcast address */
  122. int32 spi /* Security association, if any */
  123. ){
  124. /* Function to call with completed datagram */
  125. register struct raw_ip *rp;
  126. struct mbuf *bp1;
  127. int rxcnt = 0;
  128. register struct iplink *ipp;
  129. /* If we have a complete packet, call the next layer
  130.  * to handle the result. Note that fraghandle passes back
  131.  * a length field that does NOT include the IP header
  132.  */
  133. if(bpp == NULL || fraghandle(ip,bpp) == -1)
  134. return; /* Not done yet */
  135. /* Trim data segment if necessary. */
  136. trim_mbuf(bpp,ip->length - (IPLEN + ip->optlen));
  137. ipInDelivers++;
  138. if(Ip_trace)
  139. dumpip(iface,ip,*bpp,spi);
  140. for(rp = Raw_ip;rp != NULL;rp = rp->next){
  141. if(rp->protocol != ip->protocol)
  142. continue;
  143. rxcnt++;
  144. /* Duplicate the data portion, and put the header back on */
  145. dup_p(&bp1,*bpp,0,len_p(*bpp));
  146. if(bp1 != NULL){
  147. htonip(ip,&bp1,IP_CS_OLD);
  148. enqueue(&rp->rcvq,&bp1);
  149. if(rp->r_upcall != NULL)
  150. (*rp->r_upcall)(rp);
  151. } else {
  152. free_p(&bp1);
  153. }
  154. }
  155. /* Look it up in the transport protocol table */
  156. for(ipp = Iplink;ipp->funct != NULL;ipp++){
  157. if(ipp->proto == ip->protocol)
  158. break;
  159. }
  160. if(ipp->funct != NULL){
  161. /* Found, call transport protocol */
  162. (*ipp->funct)(iface,ip,bpp,rxbroadcast,spi);
  163. } else {
  164. /* Not found */
  165. if(rxcnt == 0){
  166. /* Send an ICMP Protocol Unknown response... */
  167. ipInUnknownProtos++;
  168. /* ...unless it's a broadcast */
  169. if(!rxbroadcast){
  170. icmp_output(ip,*bpp,ICMP_DEST_UNREACH,
  171.  ICMP_PROT_UNREACH,NULL);
  172. }
  173. }
  174. free_p(bpp);
  175. }
  176. }
  177. /* Handle IP packets encapsulated inside IP */
  178. void
  179. ipip_recv(
  180. struct iface *iface, /* Incoming interface */
  181. struct ip *ip, /* Extracted IP header */
  182. struct mbuf **bpp, /* Data portion */
  183. int rxbroadcast, /* True if received on subnet broadcast address */
  184. int32 spi
  185. ){
  186. net_route(&Encap,bpp);
  187. }
  188. /* Process IP datagram fragments
  189.  * If datagram is complete, return its length (MINUS header);
  190.  * otherwise return -1
  191.  */
  192. static int
  193. fraghandle(
  194. struct ip *ip, /* IP header, host byte order */
  195. struct mbuf **bpp /* The fragment itself */
  196. ){
  197. register struct reasm *rp; /* Pointer to reassembly descriptor */
  198. struct frag *lastfrag,*nextfrag,*tfp;
  199. struct mbuf *tbp;
  200. uint16 i;
  201. uint16 last; /* Index of first byte beyond fragment */
  202. last = ip->offset + ip->length - (IPLEN + ip->optlen);
  203. rp = lookup_reasm(ip);
  204. if(ip->offset == 0 && !ip->flags.mf){
  205. /* Complete datagram received. Discard any earlier fragments */
  206. if(rp != NULL){
  207. free_reasm(rp);
  208. ipReasmOKs++;
  209. }
  210. return ip->length;
  211. }
  212. ipReasmReqds++;
  213. if(rp == NULL){
  214. /* First fragment; create new reassembly descriptor */
  215. if((rp = creat_reasm(ip)) == NULL){
  216. /* No space for descriptor, drop fragment */
  217. ipReasmFails++;
  218. free_p(bpp);
  219. return -1;
  220. }
  221. }
  222. /* Keep restarting timer as long as we keep getting fragments */
  223. stop_timer(&rp->timer);
  224. start_timer(&rp->timer);
  225. /* If this is the last fragment, we now know how long the
  226.  * entire datagram is; record it
  227.  */
  228. if(!ip->flags.mf)
  229. rp->length = last;
  230. /* Set nextfrag to the first fragment which begins after us,
  231.  * and lastfrag to the last fragment which begins before us
  232.  */
  233. lastfrag = NULL;
  234. for(nextfrag = rp->fraglist;nextfrag != NULL;nextfrag = nextfrag->next){
  235. if(nextfrag->offset > ip->offset)
  236. break;
  237. lastfrag = nextfrag;
  238. }
  239. /* Check for overlap with preceeding fragment */
  240. if(lastfrag != NULL  && ip->offset < lastfrag->last){
  241. /* Strip overlap from new fragment */
  242. i = lastfrag->last - ip->offset;
  243. pullup(bpp,NULL,i);
  244. if(*bpp == NULL)
  245. return -1; /* Nothing left */
  246. ip->offset += i;
  247. }
  248. /* Look for overlap with succeeding segments */
  249. for(; nextfrag != NULL; nextfrag = tfp){
  250. tfp = nextfrag->next; /* save in case we delete fp */
  251. if(nextfrag->offset >= last)
  252. break; /* Past our end */
  253. /* Trim the front of this entry; if nothing is
  254.  * left, remove it.
  255.  */
  256. i = last - nextfrag->offset;
  257. pullup(&nextfrag->buf,NULL,i);
  258. if(nextfrag->buf == NULL){
  259. /* superseded; delete from list */
  260. if(nextfrag->prev != NULL)
  261. nextfrag->prev->next = nextfrag->next;
  262. else
  263. rp->fraglist = nextfrag->next;
  264. if(tfp->next != NULL)
  265. nextfrag->next->prev = nextfrag->prev;
  266. freefrag(nextfrag);
  267. } else
  268. nextfrag->offset = last;
  269. }
  270. /* Lastfrag now points, as before, to the fragment before us;
  271.  * nextfrag points at the next fragment. Check to see if we can
  272.  * join to either or both fragments.
  273.  */
  274. i = INSERT;
  275. if(lastfrag != NULL && lastfrag->last == ip->offset)
  276. i |= APPEND;
  277. if(nextfrag != NULL && nextfrag->offset == last)
  278. i |= PREPEND;
  279. switch(i){
  280. case INSERT: /* Insert new desc between lastfrag and nextfrag */
  281. tfp = newfrag(ip->offset,last,bpp);
  282. tfp->prev = lastfrag;
  283. tfp->next = nextfrag;
  284. if(lastfrag != NULL)
  285. lastfrag->next = tfp; /* Middle of list */
  286. else
  287. rp->fraglist = tfp; /* First on list */
  288. if(nextfrag != NULL)
  289. nextfrag->prev = tfp;
  290. break;
  291. case APPEND: /* Append to lastfrag */
  292. append(&lastfrag->buf,bpp);
  293. lastfrag->last = last; /* Extend forward */
  294. break;
  295. case PREPEND: /* Prepend to nextfrag */
  296. tbp = nextfrag->buf;
  297. nextfrag->buf = *bpp;
  298. bpp = NULL;
  299. append(&nextfrag->buf,&tbp);
  300. nextfrag->offset = ip->offset; /* Extend backward */
  301. break;
  302. case (APPEND|PREPEND):
  303. /* Consolidate by appending this fragment and nextfrag
  304.  * to lastfrag and removing the nextfrag descriptor
  305.  */
  306. append(&lastfrag->buf,bpp);
  307. append(&lastfrag->buf,&nextfrag->buf);
  308. nextfrag->buf = NULL;
  309. lastfrag->last = nextfrag->last;
  310. /* Finally unlink and delete the now unneeded nextfrag */
  311. lastfrag->next = nextfrag->next;
  312. if(nextfrag->next != NULL)
  313. nextfrag->next->prev = lastfrag;
  314. freefrag(nextfrag);
  315. break;
  316. }
  317. if(rp->fraglist->offset == 0 && rp->fraglist->next == NULL 
  318. && rp->length != 0){
  319. /* We've gotten a complete datagram, so extract it from the
  320.  * reassembly buffer and pass it on.
  321.  */
  322. *bpp = rp->fraglist->buf;
  323. rp->fraglist->buf = NULL;
  324. /* Tell IP the entire length */
  325. ip->length = rp->length + (IPLEN + ip->optlen);
  326. free_reasm(rp);
  327. ipReasmOKs++;
  328. ip->offset = 0;
  329. ip->flags.mf = 0;
  330. return ip->length;
  331. } else
  332. return -1;
  333. }
  334. /* Arrange for receipt of raw IP datagrams */
  335. struct raw_ip *
  336. raw_ip(
  337. int protocol,
  338. void (*r_upcall)()
  339. ){
  340. register struct raw_ip *rp;
  341. rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  342. rp->protocol = protocol;
  343. rp->r_upcall = r_upcall;
  344. rp->next = Raw_ip;
  345. Raw_ip = rp;
  346. return rp;
  347. }
  348. /* Free a raw IP descriptor */
  349. void
  350. del_ip(
  351. struct raw_ip *rpp
  352. ){
  353. struct raw_ip *rplast = NULL;
  354. register struct raw_ip *rp;
  355. /* Do sanity check on arg */
  356. for(rp = Raw_ip;rp != NULL;rplast=rp,rp = rp->next)
  357. if(rp == rpp)
  358. break;
  359. if(rp == NULL)
  360. return; /* Doesn't exist */
  361. /* Unlink */
  362. if(rplast != NULL)
  363. rplast->next = rp->next;
  364. else
  365. Raw_ip = rp->next;
  366. /* Free resources */
  367. free_q(&rp->rcvq);
  368. free(rp);
  369. }
  370. static struct reasm *
  371. lookup_reasm(
  372. struct ip *ip
  373. ){
  374. register struct reasm *rp;
  375. struct reasm *rplast = NULL;
  376. for(rp = Reasmq;rp != NULL;rplast=rp,rp = rp->next){
  377. if(ip->id == rp->id && ip->source == rp->source
  378.  && ip->dest == rp->dest && ip->protocol == rp->protocol){
  379. if(rplast != NULL){
  380. /* Move to top of list for speed */
  381. rplast->next = rp->next;
  382. rp->next = Reasmq;
  383. Reasmq = rp;
  384. }
  385. return rp;
  386. }
  387. }
  388. return NULL;
  389. }
  390. /* Create a reassembly descriptor,
  391.  * put at head of reassembly list
  392.  */
  393. static struct reasm *
  394. creat_reasm(
  395. struct ip *ip
  396. ){
  397. register struct reasm *rp;
  398. if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULL)
  399. return rp; /* No space for descriptor */
  400. rp->source = ip->source;
  401. rp->dest = ip->dest;
  402. rp->id = ip->id;
  403. rp->protocol = ip->protocol;
  404. set_timer(&rp->timer,ipReasmTimeout * 1000L);
  405. rp->timer.func = ip_timeout;
  406. rp->timer.arg = rp;
  407. rp->next = Reasmq;
  408. Reasmq = rp;
  409. return rp;
  410. }
  411. /* Free all resources associated with a reassembly descriptor */
  412. static void
  413. free_reasm(
  414. struct reasm *r
  415. ){
  416. register struct reasm *rp;
  417. struct reasm *rplast = NULL;
  418. register struct frag *fp;
  419. for(rp = Reasmq;rp != NULL;rplast = rp,rp=rp->next)
  420. if(r == rp)
  421. break;
  422. if(rp == NULL)
  423. return; /* Not on list */
  424. stop_timer(&rp->timer);
  425. /* Remove from list of reassembly descriptors */
  426. if(rplast != NULL)
  427. rplast->next = rp->next;
  428. else
  429. Reasmq = rp->next;
  430. /* Free any fragments on list, starting at beginning */
  431. while((fp = rp->fraglist) != NULL){
  432. rp->fraglist = fp->next;
  433. free_p(&fp->buf);
  434. free(fp);
  435. }
  436. free(rp);
  437. }
  438. /* Handle reassembly timeouts by deleting all reassembly resources */
  439. static void
  440. ip_timeout(
  441. void *arg
  442. ){
  443. free_reasm((struct reasm *)arg);
  444. ipReasmFails++;
  445. }
  446. /* Create a fragment */
  447. static struct frag *
  448. newfrag(
  449. uint16 offset,
  450. uint16 last,
  451. struct mbuf **bpp
  452. ){
  453. struct frag *fp;
  454. if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULL){
  455. /* Drop fragment */
  456. free_p(bpp);
  457. return NULL;
  458. }
  459. fp->buf = *bpp;
  460. *bpp = NULL;
  461. fp->offset = offset;
  462. fp->last = last;
  463. return fp;
  464. }
  465. /* Delete a fragment, return next one on queue */
  466. static void
  467. freefrag(
  468. struct frag *fp
  469. ){
  470. free_p(&fp->buf);
  471. free(fp);
  472. }
  473. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  474.  * each fragment on each reassembly descriptor
  475.  */
  476. void
  477. ip_garbage(
  478. int red
  479. ){
  480. struct reasm *rp,*rp1;
  481. struct frag *fp;
  482. struct raw_ip *rwp;
  483. struct iface *ifp;
  484. /* Run through the reassembly queue */
  485. for(rp = Reasmq;rp != NULL;rp = rp1){
  486. rp1 = rp->next;
  487. if(red){
  488. free_reasm(rp);
  489. } else {
  490. for(fp = rp->fraglist;fp != NULL;fp = fp->next){
  491. mbuf_crunch(&fp->buf);
  492. }
  493. }
  494. }
  495. /* Run through the raw IP queue */
  496. for(rwp = Raw_ip;rwp != NULL;rwp = rwp->next)
  497. mbuf_crunch(&rwp->rcvq);
  498. /* Walk through interface output queues and decrement IP TTLs.
  499.  * Discard and return ICMP TTL exceeded messages for any that
  500.  * go to zero. (Some argue that this ought to be done all the
  501.  * time, but it would probably break a lot of machines with
  502.  * small IP TTL settings using amateur packet radio paths.)
  503.  *
  504.  * Also send an ICMP source quench message to one
  505.  * randomly chosen packet on each queue. If in red mode,
  506.  * also drop the packet.
  507.  */
  508. for(ifp=Ifaces;ifp != NULL;ifp = ifp->next){
  509. ttldec(ifp);
  510. rquench(ifp,red);
  511. }
  512. }
  513. /* Decrement the IP TTL field in each packet on the send queue. If
  514.  * a TTL goes to zero, discard the packet.
  515.  */
  516. void
  517. ttldec(
  518. struct iface *ifp
  519. ){
  520. struct mbuf *bp,*bpprev,*bpnext;
  521. struct qhdr qhdr;
  522. struct ip ip;
  523. bpprev = NULL;
  524. for(bp = ifp->outq; bp != NULL;bpprev = bp,bp = bpnext){
  525. bpnext = bp->anext;
  526. pullup(&bp,&qhdr,sizeof(qhdr));
  527. ntohip(&ip,&bp);
  528. if(--ip.ttl == 0){
  529. /* Drop packet */
  530. icmp_output(&ip,bp,ICMP_TIME_EXCEED,0,NULL);
  531. if(bpprev == NULL) /* First on queue */
  532. ifp->outq = bpnext;
  533. else
  534. bpprev->anext = bpnext;
  535. free_p(&bp);
  536. bp = bpprev; 
  537. continue;
  538. }
  539. /* Put IP and queue headers back, restore to queue */
  540. htonip(&ip,&bp,0);
  541. pushdown(&bp,&qhdr,sizeof(qhdr));
  542. if(bpprev == NULL) /* First on queue */
  543. ifp->outq = bp;
  544. else
  545. bpprev->anext = bp;
  546. bp->anext = bpnext;
  547. }
  548. }
  549. /* Execute random quench algorithm on an interface's output queue */
  550. void
  551. rquench(
  552. struct iface *ifp,
  553. int drop
  554. ){
  555. struct mbuf *bp,*bplast;
  556. int i;
  557. struct qhdr qhdr;
  558. struct ip ip;
  559. struct mbuf *bpdup;
  560. if((i = len_q(ifp->outq)) == 0)
  561. return; /* Queue is empty */
  562. i = urandom(i); /* Select a victim */
  563. /* Search for i-th message on queue */
  564. bplast = NULL;
  565. for(bp = ifp->outq;bp != NULL && i>0;i--,bplast=bp,bp=bp->anext)
  566. ;
  567. if(bp == NULL)
  568. return; /* "Can't happen" */
  569. /* Send a source quench */
  570. dup_p(&bpdup,bp,0,len_p(bp));
  571. pullup(&bpdup,&qhdr,sizeof(qhdr));
  572. ntohip(&ip,&bpdup);
  573. icmp_output(&ip,bpdup,ICMP_QUENCH,0,NULL);
  574. free_p(&bpdup);
  575. if(!drop)
  576. return; /* All done */
  577. /* Drop the packet */
  578. if(bplast != NULL)
  579. bplast->anext = bp->anext;
  580. else
  581. ifp->outq = bp->anext; /* First on list */
  582. free_p(&bp);
  583. }