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

TCP/IP协议栈

开发平台:

Visual C++

  1. /* Low level TCP routines:
  2.  *  control block management
  3.  *  sequence number logical operations
  4.  *  state transitions
  5.  *  RTT cacheing
  6.  *  garbage collection
  7.  *
  8.  * Copyright 1991 Phil Karn, KA9Q
  9.  */
  10. #include <stdio.h>
  11. #include "global.h"
  12. #include "timer.h"
  13. #include "mbuf.h"
  14. #include "netuser.h"
  15. #include "internet.h"
  16. #include "tcp.h"
  17. #include "ip.h"
  18. /* TCP connection states */
  19. char *Tcpstates[] = {
  20. "",
  21. "Closed",
  22. "Listen",
  23. "SYN sent",
  24. "SYN recv",
  25. "Estab",
  26. "FINwait1",
  27. "FINwait2",
  28. "Closewait",
  29. "Last ACK",
  30. "Closing",
  31. "Timewait"
  32. };
  33. /* TCP closing reasons */
  34. char *Tcpreasons[] = {
  35. "Normal",
  36. "Reset/Refused",
  37. "Timeout", /* Not actually used */
  38. "ICMP" /* Not actually used */
  39. };
  40. struct tcb *Tcbs; /* Head of control block list */
  41. uint16 Tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
  42. int32 Tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
  43. int Tcp_trace; /* State change tracing flag */
  44. int Tcp_syndata;
  45. struct tcp_rtt Tcp_rtt[RTTCACHE];
  46. struct mib_entry Tcp_mib[] = {
  47. NULL, 0,
  48. "tcpRtoAlgorithm", 4, /* Van Jacobsen's algorithm */
  49. "tcpRtoMin", 0, /* No lower bound */
  50. "tcpRtoMax", MAXINT32, /* No upper bound */
  51. "tcpMaxConn", -1L, /* No limit */
  52. "tcpActiveOpens", 0,
  53. "tcpPassiveOpens", 0,
  54. "tcpAttemptFails", 0,
  55. "tcpEstabResets", 0,
  56. "tcpCurrEstab", 0,
  57. "tcpInSegs", 0,
  58. "tcpOutSegs", 0,
  59. "tcpRetransSegs", 0,
  60. NULL, 0, /* Connection state goes here */
  61. "tcpInErrs", 0,
  62. "tcpOutRsts", 0,
  63. };
  64. /* Look up TCP connection
  65.  * Return TCB pointer or NULL if nonexistant.
  66.  * Also move the entry to the top of the list to speed future searches.
  67.  */
  68. struct tcb *
  69. lookup_tcb(conn)
  70. register struct connection *conn;
  71. {
  72. register struct tcb *tcb;
  73. struct tcb *tcblast = NULL;
  74. for(tcb=Tcbs;tcb != NULL;tcblast = tcb,tcb = tcb->next){
  75. /* Yet another structure compatibility hack */
  76. if(conn->remote.port == tcb->conn.remote.port
  77.  && conn->local.port == tcb->conn.local.port
  78.  && conn->remote.address == tcb->conn.remote.address
  79.  && conn->local.address == tcb->conn.local.address){
  80. if(tcblast != NULL){
  81. /* Move to top of list */
  82. tcblast->next = tcb->next;
  83. tcb->next = Tcbs;
  84. Tcbs = tcb;
  85. }
  86. return tcb;
  87. }
  88. }
  89. return NULL;
  90. }
  91. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  92. struct tcb *
  93. create_tcb(conn)
  94. struct connection *conn;
  95. {
  96. register struct tcb *tcb;
  97. struct tcp_rtt *tp;
  98. if((tcb = lookup_tcb(conn)) != NULL)
  99. return tcb;
  100. tcb = (struct tcb *)callocw(1,sizeof (struct tcb));
  101. ASSIGN(tcb->conn,*conn);
  102. tcb->state = TCP_CLOSED;
  103. tcb->cwind = tcb->mss = Tcp_mss;
  104. tcb->ssthresh = 65535;
  105. if((tp = rtt_get(tcb->conn.remote.address)) != NULL){
  106. tcb->srtt = tp->srtt;
  107. tcb->mdev = tp->mdev;
  108. } else {
  109. tcb->srtt = Tcp_irtt; /* mdev = 0 */
  110. }
  111. /* Initialize timer intervals */
  112. set_timer(&tcb->timer,tcb->srtt);
  113. tcb->timer.func = tcp_timeout;
  114. tcb->timer.arg = tcb;
  115. tcb->next = Tcbs;
  116. Tcbs = tcb;
  117. return tcb;
  118. }
  119. /* Close our TCB */
  120. void
  121. close_self(tcb,reason)
  122. register struct tcb *tcb;
  123. int reason;
  124. {
  125. struct reseq *rp1;
  126. register struct reseq *rp;
  127. if(tcb == NULL)
  128. return;
  129. stop_timer(&tcb->timer);
  130. tcb->reason = reason;
  131. /* Flush reassembly queue; nothing more can arrive */
  132. for(rp = tcb->reseq;rp != NULL;rp = rp1){
  133. rp1 = rp->next;
  134. free_p(&rp->bp);
  135. free(rp);
  136. }
  137. tcb->reseq = NULL;
  138. settcpstate(tcb,TCP_CLOSED);
  139. }
  140. /* Sequence number comparisons
  141.  * Return true if x is between low and high inclusive,
  142.  * false otherwise
  143.  */
  144. int
  145. seq_within(x,low,high)
  146. register int32 x,low,high;
  147. {
  148. if(low <= high){
  149. if(low <= x && x <= high)
  150. return 1;
  151. } else {
  152. if(low >= x && x >= high)
  153. return 1;
  154. }
  155. return 0;
  156. }
  157. int
  158. seq_lt(x,y)
  159. register int32 x,y;
  160. {
  161. return (long)(x-y) < 0;
  162. }
  163. #ifdef notdef
  164. int
  165. seq_le(x,y)
  166. register int32 x,y;
  167. {
  168. return (long)(x-y) <= 0;
  169. }
  170. #endif /* notdef */
  171. int
  172. seq_gt(x,y)
  173. register int32 x,y;
  174. {
  175. return (long)(x-y) > 0;
  176. }
  177. int
  178. seq_ge(x,y)
  179. register int32 x,y;
  180. {
  181. return (long)(x-y) >= 0;
  182. }
  183. void
  184. settcpstate(tcb,newstate)
  185. register struct tcb *tcb;
  186. enum tcp_state newstate;
  187. {
  188. enum tcp_state oldstate;
  189. oldstate = tcb->state;
  190. tcb->state = newstate;
  191. if(Tcp_trace)
  192. printf("TCB %p %s -> %sn",tcb,
  193.  Tcpstates[oldstate],Tcpstates[newstate]);
  194. /* Update MIB variables */
  195. switch(oldstate){
  196. case TCP_CLOSED:
  197. if(newstate == TCP_SYN_SENT)
  198. tcpActiveOpens++;
  199. break;
  200. case TCP_LISTEN:
  201. if(newstate == TCP_SYN_RECEIVED)
  202. tcpPassiveOpens++;
  203. break;
  204. case TCP_SYN_SENT:
  205. if(newstate == TCP_CLOSED)
  206. tcpAttemptFails++; 
  207. break;
  208. case TCP_SYN_RECEIVED:
  209. switch(newstate){
  210. case TCP_CLOSED:
  211. case TCP_LISTEN:
  212. tcpAttemptFails++; 
  213. break;
  214. }
  215. break;
  216. case TCP_ESTABLISHED:
  217. case TCP_CLOSE_WAIT:
  218. switch(newstate){
  219. case TCP_CLOSED:
  220. case TCP_LISTEN:
  221. tcpEstabResets++;
  222. break;
  223. }
  224. tcpCurrEstab--;
  225. break;
  226. }
  227. if(newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
  228. tcpCurrEstab++;
  229. if(tcb->s_upcall)
  230. (*tcb->s_upcall)(tcb,oldstate,newstate);
  231. switch(newstate){
  232. case TCP_SYN_RECEIVED: /***/
  233. case TCP_ESTABLISHED:
  234. /* Notify the user that he can begin sending data */
  235. if(tcb->t_upcall)
  236. (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  237. break;
  238. }
  239. }
  240. /* Round trip timing cache routines.
  241.  * These functions implement a very simple system for keeping track of
  242.  * network performance for future use in new connections.
  243.  * The emphasis here is on speed of update (rather than optimum cache hit
  244.  * ratio) since rtt_add is called every time a TCP connection updates
  245.  * its round trip estimate.
  246.  */
  247. void
  248. rtt_add(addr,rtt)
  249. int32 addr; /* Destination IP address */
  250. int32 rtt;
  251. {
  252. register struct tcp_rtt *tp;
  253. int32 abserr;
  254. if(addr == 0)
  255. return;
  256. tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  257. if(tp->addr != addr){
  258. /* New entry */
  259. tp->addr = addr;
  260. tp->srtt = rtt;
  261. tp->mdev = 0;
  262. } else {
  263. /* Run our own SRTT and MDEV integrators, with rounding */
  264. abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  265. tp->srtt = ((AGAIN-1)*tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  266. tp->mdev = ((DGAIN-1)*tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  267. }
  268. }
  269. struct tcp_rtt *
  270. rtt_get(addr)
  271. int32 addr;
  272. {
  273. register struct tcp_rtt *tp;
  274. if(addr == 0)
  275. return NULL;
  276. tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  277. if(tp->addr != addr)
  278. return NULL;
  279. return tp;
  280. }
  281. /* TCP garbage collection - called by storage allocator when free space
  282.  * runs low. The send and receive queues are crunched. If the situation
  283.  * is red, the resequencing queue is discarded; otherwise it is
  284.  * also crunched.
  285.  */
  286. void
  287. tcp_garbage(red)
  288. int red;
  289. {
  290. register struct tcb *tcb;
  291. struct reseq *rp,*rp1;
  292. for(tcb = Tcbs;tcb != NULL;tcb = tcb->next){
  293. mbuf_crunch(&tcb->rcvq);
  294. mbuf_crunch(&tcb->sndq);
  295. for(rp = tcb->reseq;rp != NULL;rp = rp1){
  296. rp1 = rp->next;
  297. if(red){
  298. free_p(&rp->bp);
  299. free(rp);
  300. } else {
  301. mbuf_crunch(&rp->bp);
  302. }
  303. }
  304. if(red)
  305. tcb->reseq = NULL;
  306. }
  307. }