Subversion Repositories Kolibri OS

Rev

Rev 922 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
431 serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
983 diamond 3
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
431 serge 4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;  TCP.INC                                                     ;;
7
;;                                                              ;;
8
;;  TCP Processes for Menuet OS  TCP/IP stack                   ;;
9
;;                                                              ;;
10
;;  Copyright 2002 Mike Hibbett, mikeh@oceanfree.net            ;;
11
;;                                                              ;;
12
;;  See file COPYING for details                                ;;
13
;;  v0.6 : Added reset handling in the established state        ;;
14
;;         Added a timer per socket to allow delays when        ;;
15
;;         rx window gets below 1KB                             ;;
907 mikedld 16
;;                                                              ;;
431 serge 17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1 ha 18
 
593 mikedld 19
$Revision: 983 $
20
 
21
 
261 hidnplayr 22
; TCP TCB states
907 mikedld 23
TCB_LISTEN	   equ	      1
24
TCB_SYN_SENT	   equ	      2
25
TCB_SYN_RECEIVED   equ	      3
26
TCB_ESTABLISHED    equ	      4
27
TCB_FIN_WAIT_1	   equ	      5
28
TCB_FIN_WAIT_2	   equ	      6
29
TCB_CLOSE_WAIT	   equ	      7
30
TCB_CLOSING	   equ	      8
31
TCB_LAST_ACK	   equ	      9
32
TCB_TIMED_WAIT	   equ	      10
33
TCB_CLOSED	   equ	      11
1 ha 34
 
907 mikedld 35
TH_FIN	= 0x01
36
TH_SYN	= 0x02
37
TH_RST	= 0x04
38
TH_PUSH = 0x08
39
TH_ACK	= 0x10
40
TH_URG	= 0x20
261 hidnplayr 41
 
907 mikedld 42
TWOMSL		    equ     10	    ; # of secs to wait before closing socket
261 hidnplayr 43
 
907 mikedld 44
TCP_RETRIES	    equ 	5		; Number of times to resend a packet
45
TCP_TIMEOUT	    equ 	10		; resend if not replied to in x hs
46
 
1 ha 47
;*******************************************************************
48
;   Interface
49
;
50
;       tcp_tx_handler      Handles the TCP transmit queue
51
;       tcp_rx              The protocol handler for received data
52
;       buildTCPPacket      fills in the packet headers and data
53
;       tcpStateMachine     Main state machine for received TCP packets
54
;       tcp_tcb_handler     1s timer, to erase tcb's in TIME_WAIT state
55
;
56
;*******************************************************************
57
 
58
 
261 hidnplayr 59
;   TCP Payload ( Data field in IP datagram )
60
;
61
;    0                   1                   2                   3
62
;    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
63
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64
;20 |          Source Port          |       Destination Port        |
65
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66
;24 |                        Sequence Number                        |
67
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68
;28 |                    Acknowledgment Number                      |
69
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70
;32 |  Data |           |U|A|P|R|S|F|                               |
71
;   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
72
;   |       |           |G|K|H|T|N|N|                               |
73
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74
;36 |           Checksum            |         Urgent Pointer        |
75
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76
;40 |                    Options                    |    Padding    |
77
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78
;   |                             data
1 ha 79
 
261 hidnplayr 80
 
81
struc TCP_PACKET
907 mikedld 82
{  .SourcePort	     dw  ?  ;+00
261 hidnplayr 83
   .DestinationPort  dw  ?  ;+02
84
   .SequenceNumber   dd  ?  ;+04
907 mikedld 85
   .AckNumber	     dd  ?  ;+08
86
   .DataOffset	     db  ?  ;+12 - DataOffset[0-3 bits] and Reserved[4-7]
87
   .Flags	     db  ?  ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
88
   .Window	     dw  ?  ;+14
89
   .Checksum	     dw  ?  ;+16
261 hidnplayr 90
   .UrgentPointer    dw  ?  ;+18
907 mikedld 91
   .Options	     rb  3  ;+20
92
   .Padding	     db  ?  ;+23
93
   .Data	     db  ?  ;+24
261 hidnplayr 94
}
95
 
96
virtual at 0
97
  TCP_PACKET TCP_PACKET
98
end virtual
99
 
100
 
101
 
1 ha 102
;***************************************************************************
103
;   Function
104
;      tcp_tcb_handler
105
;
106
;   Description
107
;       Handles sockets in the timewait state, closing them
108
;       when the TCB timer expires
109
;
110
;***************************************************************************
111
 
907 mikedld 112
proc tcp_tcb_handler stdcall uses ebx
113
	; scan through all the sockets, decrementing active timers
1 ha 114
 
907 mikedld 115
	mov	ebx, net_sockets
1 ha 116
 
907 mikedld 117
	cmp	[ebx + SOCKET.NextPtr], 0
118
	je	.exit
119
	DEBUGF	1, "K : sockets:\n"
1 ha 120
 
907 mikedld 121
  .next_socket:
122
	mov	ebx, [ebx + SOCKET.NextPtr]
123
	or	ebx, ebx
124
	jz	.exit
1 ha 125
 
922 mikedld 126
	DEBUGF	1, "K :   %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState]
1 ha 127
 
907 mikedld 128
	cmp	[ebx + SOCKET.TCBTimer], 0
129
	jne	.decrement_tcb
130
	cmp	[ebx + SOCKET.wndsizeTimer], 0
131
	jne	.decrement_wnd
132
	jmp	.next_socket
1 ha 133
 
907 mikedld 134
  .decrement_tcb:
135
	; decrement it, delete socket if TCB timer = 0 & socket in timewait state
136
	dec	[ebx + SOCKET.TCBTimer]
137
	jnz	.next_socket
1 ha 138
 
907 mikedld 139
	cmp	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
140
	jne	.next_socket
1 ha 141
 
907 mikedld 142
	push	[ebx + SOCKET.PrevPtr]
143
	stdcall net_socket_free, ebx
144
	pop	ebx
145
	jmp	.next_socket
1 ha 146
 
907 mikedld 147
  .decrement_wnd:
148
	; TODO - prove it works!
149
	dec	[ebx + SOCKET.wndsizeTimer]
150
	jmp	.next_socket
1 ha 151
 
907 mikedld 152
  .exit:
153
	ret
154
endp
1 ha 155
 
156
 
157
;***************************************************************************
158
;   Function
159
;      tcp_tx_handler
160
;
161
;   Description
162
;       Handles queued TCP data
163
;       This is a kernel function, called by stack_handler
164
;
165
;***************************************************************************
907 mikedld 166
 
167
proc tcp_tx_handler stdcall
1 ha 168
    ; decrement all resend buffers timers. If they
169
    ; expire, queue them for sending, and restart the timer.
170
    ; If the retries counter reach 0, delete the entry
171
 
907 mikedld 172
	mov	esi, resendQ
173
	mov	ecx, 0
1 ha 174
 
907 mikedld 175
  .next_resendq:
176
	cmp	ecx, NUMRESENDENTRIES
177
	je	.exit		    ; None left
178
	cmp	dword[esi + 4], 0
179
	jne	@f		     ; found one
180
	inc	ecx
181
	add	esi, 8
182
	jmp	.next_resendq
1 ha 183
 
907 mikedld 184
    @@: ; we have one. decrement it's timer by 1
185
	dec	word[esi + 2]
186
	jz	@f
187
	inc	ecx
188
	add	esi, 8
189
	jmp	.next_resendq	    ; Timer not zero, so move on
1 ha 190
 
907 mikedld 191
    @@:
192
	xor	ebx, ebx
193
	; restart timer, and decrement retries
194
	; After the first resend, back of on next, by a factor of 5
195
	mov	[esi + 2], word TCP_TIMEOUT * 5
196
	dec	byte[esi + 1]
197
	jnz	@f
1 ha 198
 
907 mikedld 199
	; retries now 0, so delete from queue
200
	xchg	 [esi + 4], ebx
1 ha 201
 
907 mikedld 202
    @@: ; resend packet
203
	pushad
1 ha 204
 
907 mikedld 205
	mov	eax, EMPTY_QUEUE
206
	call	dequeue
207
	cmp	ax, NO_BUFFER
208
	jne	.tth004z
1 ha 209
 
907 mikedld 210
	; TODO - try again in 10ms.
211
	test	ebx, ebx
212
	jnz	@f
213
	mov	[esi + 4], ebx
1 ha 214
 
907 mikedld 215
    @@: ; Mark it to expire in 10ms - 1 tick
216
	mov	byte[esi + 1], 1
217
	mov	word[esi + 2], 1
218
	jmp	.tth005
1 ha 219
 
907 mikedld 220
  .tth004z:
221
	; we have a buffer # in ax
222
	push	eax ecx
223
	mov	ecx, IPBUFFSIZE
224
	mul	ecx
225
	add	eax, IPbuffs
1 ha 226
 
907 mikedld 227
	; we have the buffer address in eax
228
	mov	edi, eax
229
	pop	ecx
230
	; Now get buffer location, and copy buffer across. argh! more copying,,
231
	mov	esi, resendBuffer
232
    @@: add	esi, IPBUFFSIZE
233
	loop	@b
1 ha 234
 
907 mikedld 235
	; we have resend buffer location in esi
236
	mov	ecx, IPBUFFSIZE
1 ha 237
 
907 mikedld 238
	; copy data across
239
	push	edi
240
	cld
241
	rep	movsb
242
	pop	edi
1 ha 243
 
907 mikedld 244
	; queue packet
245
	mov	eax, NET1OUT_QUEUE
246
	mov	edx, [stack_ip]
247
	cmp	edx, [edi + IP_PACKET.DestinationAddress]
248
	jne	.not_local
249
	mov	eax, IPIN_QUEUE
1 ha 250
 
907 mikedld 251
  .not_local:
252
	pop	ebx
253
	call	queue
1 ha 254
 
907 mikedld 255
  .tth005:
256
	popad
1 ha 257
 
907 mikedld 258
	inc	ecx
259
	add	esi, 8
260
	jmp	.next_resendq
1 ha 261
 
907 mikedld 262
  .exit:
263
	ret
264
endp
1 ha 265
 
266
 
267
;***************************************************************************
268
;   Function
269
;      tcp_rx
270
;
271
;   Description
272
;       TCP protocol handler
273
;       This is a kernel function, called by ip_rx
274
;       IP buffer address given in edx
275
;          IP buffer number in eax
276
;          Free up (or re-use) IP buffer when finished
277
;
278
;***************************************************************************
279
 
907 mikedld 280
proc tcp_rx stdcall uses ebx
281
	; The process is as follows.
282
	; Look for a socket with matching remote IP, remote port, local port
283
	; if not found, then
284
	; look for remote IP + local port match ( where sockets remote port = 0)
285
	; if not found, then
286
	; look for a socket where local socket port == IP packets remote port
287
	; where sockets remote port, remote IP = 0
288
	; discard if not found
289
	; Call sockets tcbStateMachine, with pointer to packet.
290
	; the state machine will not delete the packet, so do that here.
1 ha 291
 
907 mikedld 292
	push	eax
1 ha 293
 
907 mikedld 294
	; Look for a socket where
295
	; IP Packet TCP Destination Port = local Port
296
	; IP Packet SA = Remote IP
297
	; IP Packet TCP Source Port = remote Port
1 ha 298
 
907 mikedld 299
	mov	ebx, net_sockets
1 ha 300
 
907 mikedld 301
  .next_socket.1:
302
	mov	ebx, [ebx + SOCKET.NextPtr]
303
	or	ebx, ebx
304
	jz	.next_socket.1.exit
1 ha 305
 
907 mikedld 306
;        DEBUGF  1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
1 ha 307
 
907 mikedld 308
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
309
	cmp	[ebx + SOCKET.LocalPort], ax		; get the dest. port from the TCP hdr
310
	jne	.next_socket.1				; different - try next socket
1 ha 311
 
907 mikedld 312
;        DEBUGF  1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
1 ha 313
 
907 mikedld 314
	mov	eax, [edx + IP_PACKET.SourceAddress]	; get the source IP Addr from the IP hdr
315
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
316
	jne	.next_socket.1				; different - try next socket
1 ha 317
 
907 mikedld 318
;        DEBUGF  1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
1 ha 319
 
907 mikedld 320
	mov	ax, [edx + 20 + TCP_PACKET.SourcePort]	; get the source port from the TCP hdr
321
	cmp	[ebx + SOCKET.RemotePort], ax		; compare with socket's remote port
322
	jne	.next_socket.1				; different - try next socket
1 ha 323
 
907 mikedld 324
	; We have a complete match - use this socket
325
	jmp	.change_state
1 ha 326
 
907 mikedld 327
  .next_socket.1.exit:
1 ha 328
 
907 mikedld 329
	; If we got here, there was no match
330
	; Look for a socket where
331
	; IP Packet TCP Destination Port = local Port
332
	; IP Packet SA = Remote IP
333
	; socket remote Port = 0
1 ha 334
 
907 mikedld 335
	mov	ebx, net_sockets
1 ha 336
 
907 mikedld 337
  .next_socket.2:
338
	mov	ebx, [ebx + SOCKET.NextPtr]
339
	or	ebx, ebx
340
	jz	.next_socket.2.exit
1 ha 341
 
907 mikedld 342
;        DEBUGF  1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
1 ha 343
 
907 mikedld 344
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
345
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
346
	jne	.next_socket.2				; different - try next socket
1 ha 347
 
907 mikedld 348
;        DEBUGF  1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
1 ha 349
 
907 mikedld 350
	mov	eax, [edx + IP_PACKET.SourceAddress]	; get the source IP Addr from the IP hdr
351
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
352
	jne	.next_socket.2				; different - try next socket
1 ha 353
 
907 mikedld 354
;        DEBUGF  1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
1 ha 355
 
907 mikedld 356
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
357
	jne	.next_socket.2				; different - try next socket
1 ha 358
 
907 mikedld 359
	; We have a complete match - use this socket
360
	jmp	.change_state
1 ha 361
 
907 mikedld 362
  .next_socket.2.exit:
1 ha 363
 
907 mikedld 364
	; If we got here, there was no match
365
	; Look for a socket where
366
	; IP Packet TCP Destination Port = local Port
367
	; socket Remote IP = 0
368
	; socket remote Port = 0
1 ha 369
 
907 mikedld 370
	mov	ebx, net_sockets
1 ha 371
 
907 mikedld 372
  .next_socket.3:
373
	mov	ebx, [ebx + SOCKET.NextPtr]
374
	or	ebx, ebx
375
	jz	.next_socket.3.exit
1 ha 376
 
907 mikedld 377
;        DEBUGF  1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
378
 
379
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get destination port from the TCP hdr
380
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
381
	jne	.next_socket.3				; different - try next socket
382
 
383
;        DEBUGF  1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
384
 
385
	cmp	[ebx + SOCKET.RemoteIP], 0		; only match a socket remote IP of 0
386
	jne	.next_socket.3				; different - try next socket
387
 
388
;        DEBUGF  1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
389
 
390
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
391
	jne	.next_socket.3				; different - try next socket
392
 
393
	; We have a complete match - use this socket
394
	jmp	.change_state
395
 
396
  .next_socket.3.exit:
397
 
398
	; If we got here, we need to reject the packet
399
 
400
	DEBUGF	1, "K : tcp_rx - dumped\n"
401
	DEBUGF	1, "K :   --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2
922 mikedld 402
 
907 mikedld 403
	inc	[dumped_rx_count]
404
	jmp	.exit
405
 
406
  .change_state:
407
 
408
	; We have a valid socket/TCB, so call the TCB State Machine for that skt.
409
	; socket is pointed to by ebx
410
	; IP packet is pointed to by edx
411
	; IP buffer number is on stack ( it will be popped at the end)
412
 
413
	stdcall tcpStateMachine, ebx
414
 
415
  .exit:
416
	pop	eax
417
	call	freeBuff
418
	ret
419
endp
420
 
421
 
1 ha 422
;***************************************************************************
423
;   Function
424
;      buildTCPPacket
425
;
426
;   Description
427
;       builds an IP Packet with TCP data fully populated for transmission
428
;       You may destroy any and all registers
429
;          TCP control flags specified in bl
430
;          This TCB is in [sktAddr]
431
;          User data pointed to by esi
432
;       Data length in ecx
433
;          Transmit buffer number in eax
434
;
435
;***************************************************************************
436
 
907 mikedld 437
proc build_tcp_packet stdcall, sockAddr:DWORD
438
	push	ecx			   ; Save data length
1 ha 439
 
907 mikedld 440
	; convert buffer pointer eax to the absolute address
441
	mov	ecx, IPBUFFSIZE
442
	mul	ecx
443
	add	eax, IPbuffs
1 ha 444
 
907 mikedld 445
	mov	edx, eax
1 ha 446
 
907 mikedld 447
	mov	[edx + 20 + TCP_PACKET.Flags], bl		; TCP flags
1 ha 448
 
907 mikedld 449
	mov	ebx, [sockAddr]
1 ha 450
 
907 mikedld 451
	; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
1 ha 452
 
907 mikedld 453
	; Fill in the IP header ( some data is in the socket descriptor)
454
	mov	eax, [ebx + SOCKET.LocalIP]
455
	mov	[edx + IP_PACKET.SourceAddress], eax
456
	mov	eax, [ebx + SOCKET.RemoteIP]
457
	mov	[edx + IP_PACKET.DestinationAddress], eax
1 ha 458
 
907 mikedld 459
	mov	[edx + IP_PACKET.VersionAndIHL], 0x45
460
	mov	[edx + IP_PACKET.TypeOfService], 0
1 ha 461
 
907 mikedld 462
	pop	eax		      ; Get the TCP data length
463
	push	eax
1 ha 464
 
907 mikedld 465
	add	eax, 20 + 20	       ; add IP header and TCP header lengths
466
	rol	ax, 8
467
	mov	[edx + IP_PACKET.TotalLength], ax
468
	mov	[edx + IP_PACKET.Identification], 0
469
	mov	[edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
470
	mov	[edx + IP_PACKET.TimeToLive], 0x20
471
	mov	[edx + IP_PACKET.Protocol], PROTOCOL_TCP
1 ha 472
 
907 mikedld 473
	; Checksum left unfilled
474
	mov	[edx + IP_PACKET.HeaderChecksum], 0
1 ha 475
 
907 mikedld 476
	; Fill in the TCP header (some data is in the socket descriptor)
477
	mov	ax, [ebx + SOCKET.LocalPort]
478
	mov	[edx + 20 + TCP_PACKET.SourcePort], ax		; Local Port
1 ha 479
 
907 mikedld 480
	mov	ax, [ebx + SOCKET.RemotePort]
481
	mov	[edx + 20 + TCP_PACKET.DestinationPort], ax	; desitination Port
1 ha 482
 
907 mikedld 483
	; Checksum left unfilled
484
	mov	[edx + 20 + TCP_PACKET.Checksum], 0
1 ha 485
 
907 mikedld 486
	; sequence number
487
	mov	eax, [ebx + SOCKET.SND_NXT]
488
	mov	[edx + 20 + TCP_PACKET.SequenceNumber], eax
1 ha 489
 
907 mikedld 490
	; ack number
491
	mov	eax, [ebx + SOCKET.RCV_NXT]
492
	mov	[edx + 20 + TCP_PACKET.AckNumber], eax
1 ha 493
 
907 mikedld 494
	; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
495
	; 768 bytes seems better
496
	mov	[edx + 20 + TCP_PACKET.Window], 0x0003
1 ha 497
 
907 mikedld 498
	; Urgent pointer (0)
499
	mov	[edx + 20 + TCP_PACKET.UrgentPointer], 0
1 ha 500
 
907 mikedld 501
	; data offset ( 0x50 )
502
	mov	[edx + 20 + TCP_PACKET.DataOffset], 0x50
1 ha 503
 
907 mikedld 504
	pop	ecx		     ; count of bytes to send
505
	mov	ebx, ecx	    ; need the length later
1 ha 506
 
907 mikedld 507
	cmp	ebx, 0
508
	jz	@f
1 ha 509
 
907 mikedld 510
	mov	edi, edx
511
	add	edi, 40
512
	cld
513
	rep	movsb		    ; copy the data across
1 ha 514
 
907 mikedld 515
    @@: ; we have edx as IPbuffer ptr.
516
	; Fill in the TCP checksum
517
	; First, fill in pseudoheader
518
	mov	eax, [edx + IP_PACKET.SourceAddress]
519
	mov	[pseudoHeader], eax
520
	mov	eax, [edx + IP_PACKET.DestinationAddress]
521
	mov	[pseudoHeader + 4], eax
522
	mov	word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
523
	add	ebx, 20
524
	mov	[pseudoHeader + 10], bh
525
	mov	[pseudoHeader + 11], bl
1 ha 526
 
907 mikedld 527
	mov	eax, pseudoHeader
528
	mov	[checkAdd1], eax
529
	mov	word[checkSize1], 12
530
	mov	eax, edx
531
	add	eax, 20
532
	mov	[checkAdd2], eax
533
	mov	eax, ebx
534
	mov	[checkSize2], ax
1 ha 535
 
907 mikedld 536
	call	checksum
1 ha 537
 
907 mikedld 538
	; store it in the TCP checksum ( in the correct order! )
539
	mov	ax, [checkResult]
540
	rol	ax, 8
541
	mov	[edx + 20 + TCP_PACKET.Checksum], ax
1 ha 542
 
907 mikedld 543
	; Fill in the IP header checksum
544
	GET_IHL eax, edx	       ; get IP-Header length
545
	stdcall checksum_jb, edx, eax  ; buf_ptr, buf_size
546
	rol	ax, 8
547
	mov	[edx + IP_PACKET.HeaderChecksum], ax
1 ha 548
 
907 mikedld 549
	ret
550
endp
1 ha 551
 
552
 
553
; Increments the 32 bit value pointed to by esi in internet order
907 mikedld 554
proc inc_inet_esi stdcall
555
	push	eax
556
	mov	eax, [esi]
557
	bswap	eax
558
	inc	eax
559
	bswap	eax
560
	mov	[esi], eax
561
	pop	eax
562
	ret
563
endp
1 ha 564
 
565
 
566
; Increments the 32 bit value pointed to by esi in internet order
567
; by the value in ecx
907 mikedld 568
proc add_inet_esi stdcall
569
	push	eax
570
	mov	eax, [esi]
571
	bswap	eax
572
	add	eax, ecx
573
	bswap	eax
574
	mov	[esi], eax
575
	pop	eax
576
	ret
577
endp
1 ha 578
 
579
 
580
iglobal
907 mikedld 581
  TCBStateHandler dd \
582
    stateTCB_LISTEN, \
583
    stateTCB_SYN_SENT, \
584
    stateTCB_SYN_RECEIVED, \
585
    stateTCB_ESTABLISHED, \
586
    stateTCB_FIN_WAIT_1, \
587
    stateTCB_FIN_WAIT_2, \
588
    stateTCB_CLOSE_WAIT, \
589
    stateTCB_CLOSING, \
590
    stateTCB_LAST_ACK, \
591
    stateTCB_TIME_WAIT, \
592
    stateTCB_CLOSED
1 ha 593
endg
594
 
907 mikedld 595
 
1 ha 596
;***************************************************************************
597
;   Function
598
;      tcpStateMachine
599
;
600
;   Description
601
;       TCP state machine
602
;       This is a kernel function, called by tcp_rx
603
;
604
;       IP buffer address given in edx
907 mikedld 605
;          Socket/TCB address in ebx
1 ha 606
;
607
;       The IP buffer will be released by the caller
608
;***************************************************************************
609
 
907 mikedld 610
proc tcpStateMachine stdcall, sockAddr:DWORD
611
	; as a packet has been received, update the TCB timer
612
	mov	[ebx + SOCKET.TCBTimer], TWOMSL
1 ha 613
 
907 mikedld 614
	; If the received packet has an ACK bit set,
615
	; remove any packets in the resend queue that this
616
	; received packet acknowledges
617
	pushad
618
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
619
	jz	.call_handler					; No ACK, so no data yet
1 ha 620
 
907 mikedld 621
	; get skt number in eax
622
	stdcall net_socket_addr_to_num, ebx
1 ha 623
 
907 mikedld 624
	; The ack number is in [edx + 28], inet format
625
	; skt in eax
1 ha 626
 
907 mikedld 627
	mov	esi, resendQ
628
	xor	ecx, ecx
1 ha 629
 
907 mikedld 630
  .next_resendq:
631
	cmp	ecx, NUMRESENDENTRIES
632
	je	.call_handler	  ; None left
633
	cmp	[esi + 4], eax
634
	je	@f		  ; found one
635
	inc	ecx
636
	add	esi, 8
637
	jmp	.next_resendq
1 ha 638
 
907 mikedld 639
    @@: 		  ; Can we delete this buffer?
1 ha 640
 
907 mikedld 641
			  ; If yes, goto @@. No, goto .next_resendq
642
	; Get packet data address
1 ha 643
 
907 mikedld 644
	push	ecx
645
	; Now get buffer location, and copy buffer across. argh! more copying,,
646
	imul	edi, ecx, IPBUFFSIZE
647
	add	edi, resendBuffer
1 ha 648
 
907 mikedld 649
	; we have dest buffer location in edi. incoming packet in edx.
650
	; Get this packets sequence number
651
	; preserve al, ecx, esi, edx
652
	mov	ecx, [edi + 20 + TCP_PACKET.SequenceNumber]
653
	bswap	ecx
654
	movzx	ebx, word[edi + 2]
655
	xchg	bl, bh
656
	sub	ebx, 40
657
	add	ecx, ebx	  ; ecx is now seq# of last byte +1, intel format
1 ha 658
 
907 mikedld 659
	; get recievd ack #, in intel format
660
	mov	ebx, [edx + 20 + TCP_PACKET.AckNumber]
661
	bswap	ebx
1 ha 662
 
907 mikedld 663
	cmp	ebx, ecx	; Finally. ecx = rx'ed ack. ebx = last byte in que
664
				; DANGER! need to handle case that we have just
665
				; passed the 2**32, and wrapped round!
666
	pop	ecx
667
	jae	@f		; if rx > old, delete old
1 ha 668
 
907 mikedld 669
	inc	ecx
670
	add	esi, 8
671
	jmp	.next_resendq
1 ha 672
 
907 mikedld 673
    @@: mov	dword[esi + 4], 0
674
	inc	ecx
675
	add	esi, 8
676
	jmp	.next_resendq
1 ha 677
 
907 mikedld 678
  .call_handler:
679
	popad
1 ha 680
 
907 mikedld 681
	; Call handler for given TCB state
1 ha 682
 
907 mikedld 683
	mov	eax, [ebx + SOCKET.TCBState]
684
	cmp	eax, TCB_LISTEN
685
	jb	.exit
686
	cmp	eax, TCB_CLOSED
687
	ja	.exit
1 ha 688
 
907 mikedld 689
	stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
1 ha 690
 
907 mikedld 691
  .exit:
692
	ret
693
endp
1 ha 694
 
695
 
907 mikedld 696
proc stateTCB_LISTEN stdcall, sockAddr:DWORD
697
	; In this case, we are expecting a SYN packet
698
	; For now, if the packet is a SYN, process it, and send a response
699
	; If not, ignore it
1 ha 700
 
907 mikedld 701
	; Look at control flags
702
	test	[edx + 20 + TCP_PACKET.Flags], TH_SYN
703
	jz	.exit
1 ha 704
 
907 mikedld 705
	; We have a SYN. update the socket with this IP packets details,
706
	; And send a response
1 ha 707
 
907 mikedld 708
	mov	eax, [edx + IP_PACKET.SourceAddress]
709
	mov	[ebx + SOCKET.RemoteIP], eax
710
	mov	ax, [edx + 20 + TCP_PACKET.SourcePort]
711
	mov	[ebx + SOCKET.RemotePort], ax
712
	mov	eax, [edx + 20 + TCP_PACKET.SequenceNumber]
713
	mov	[ebx + SOCKET.IRS], eax
714
	mov	[ebx + SOCKET.RCV_NXT], eax
715
	lea	esi, [ebx + SOCKET.RCV_NXT]
716
	call	inc_inet_esi ; RCV.NXT
717
	mov	eax, [ebx + SOCKET.ISS]
718
	mov	[ebx + SOCKET.SND_NXT], eax
1 ha 719
 
907 mikedld 720
	; Now construct the response, and queue for sending by IP
721
	mov	eax, EMPTY_QUEUE
722
	call	dequeue
723
	cmp	ax, NO_BUFFER
724
	je	.exit
1 ha 725
 
907 mikedld 726
	push	eax
727
	mov	bl, TH_SYN + TH_ACK
728
	xor	ecx, ecx
729
	xor	esi, esi
730
	stdcall build_tcp_packet, [sockAddr]
1 ha 731
 
907 mikedld 732
	mov	eax, NET1OUT_QUEUE
733
	mov	edx, [stack_ip]
734
	mov	ecx, [sockAddr]
735
	cmp	edx, [ecx + SOCKET.RemoteIP]
736
	jne	.not_local
737
	mov	eax, IPIN_QUEUE
1 ha 738
 
907 mikedld 739
  .not_local:
740
	; Send it.
741
	pop	ebx
742
	call	queue
1 ha 743
 
907 mikedld 744
	mov	esi, [sockAddr]
745
	mov	[esi + SOCKET.TCBState], TCB_SYN_RECEIVED
1 ha 746
 
907 mikedld 747
	; increment SND.NXT in socket
748
	add	esi, SOCKET.SND_NXT
749
	call	inc_inet_esi
1 ha 750
 
907 mikedld 751
  .exit:
752
	ret
753
endp
1 ha 754
 
755
 
907 mikedld 756
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
757
	; We are awaiting an ACK to our SYN, with a SYM
758
	; Look at control flags - expecting an ACK
1 ha 759
 
907 mikedld 760
	mov	al, [edx + 20 + TCP_PACKET.Flags]
761
	and	al, TH_SYN + TH_ACK
762
	cmp	al, TH_SYN + TH_ACK
763
	je	.syn_ack
1 ha 764
 
907 mikedld 765
	test	al, TH_SYN
766
	jz	.exit
1 ha 767
 
907 mikedld 768
	mov	[ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
769
	push	TH_SYN + TH_ACK
770
	jmp	.send
1 ha 771
 
907 mikedld 772
  .syn_ack:
773
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
774
	push	TH_ACK
1 ha 775
 
907 mikedld 776
  .send:
777
	; Store the recv.nxt field
778
	mov	eax, [edx + 20 + TCP_PACKET.SequenceNumber]
1 ha 779
 
907 mikedld 780
	; Update our recv.nxt field
781
	mov	[ebx + SOCKET.RCV_NXT], eax
782
	lea	esi, [ebx + SOCKET.RCV_NXT]
783
	call	inc_inet_esi
1 ha 784
 
907 mikedld 785
	; Send an ACK
786
	; Now construct the response, and queue for sending by IP
787
	mov	eax, EMPTY_QUEUE
788
	call	dequeue
789
	cmp	ax, NO_BUFFER
790
	pop	ebx
791
	je	.exit
1 ha 792
 
907 mikedld 793
	push	eax
1 ha 794
 
907 mikedld 795
	xor	ecx, ecx
796
	xor	esi, esi
797
	stdcall build_tcp_packet, [sockAddr]
1 ha 798
 
907 mikedld 799
	mov	eax, NET1OUT_QUEUE
800
	mov	edx, [stack_ip]
801
	mov	ecx, [sockAddr]
802
	cmp	edx, [ecx + SOCKET.RemoteIP]
803
	jne	.not_local
804
	mov	eax, IPIN_QUEUE
1 ha 805
 
907 mikedld 806
  .not_local:
807
	; Send it.
808
	pop	ebx
809
	call	queue
1 ha 810
 
907 mikedld 811
  .exit:
812
	ret
813
endp
1 ha 814
 
815
 
907 mikedld 816
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
817
	; In this case, we are expecting an ACK packet
818
	; For now, if the packet is an ACK, process it,
819
	; If not, ignore it
1 ha 820
 
922 mikedld 821
	test	[edx + 20 + TCP_PACKET.Flags], TH_RST
822
	jz	.check_ack
1 ha 823
 
907 mikedld 824
	push	[ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
825
	pop	[ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
1 ha 826
 
922 mikedld 827
	mov	[ebx + SOCKET.TCBState], TCB_LISTEN
828
	jmp	.exit
1 ha 829
 
922 mikedld 830
  .check_ack:
907 mikedld 831
	; Look at control flags - expecting an ACK
832
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
833
	jz	.exit
1 ha 834
 
907 mikedld 835
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
1 ha 836
 
907 mikedld 837
  .exit:
838
	ret
839
endp
1 ha 840
 
841
 
907 mikedld 842
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
843
	; Here we are expecting data, or a request to close
844
	; OR both...
1 ha 845
 
907 mikedld 846
	; Did we receive a FIN or RST?
922 mikedld 847
	test	[edx + 20 + TCP_PACKET.Flags], TH_FIN
848
	jz	.check_ack
1 ha 849
 
907 mikedld 850
	; It was a fin or reset.
1 ha 851
 
907 mikedld 852
	; Remove resend entries from the queue  - I dont want to send any more data
853
	pushad
1 ha 854
 
907 mikedld 855
	; get skt #
856
	stdcall net_socket_addr_to_num, ebx
1 ha 857
 
907 mikedld 858
	mov	esi, resendQ
859
	mov	ecx, 0
1 ha 860
 
907 mikedld 861
  .next_resendq:
862
	cmp	ecx, NUMRESENDENTRIES
863
	je	.last_resendq	    ; None left
864
	cmp	[esi + 4], eax
865
	je	@f		    ; found one
866
	inc	ecx
867
	add	esi, 8
868
	jmp	.next_resendq
1 ha 869
 
907 mikedld 870
    @@: mov	dword[esi + 4], 0
871
	inc	ecx
872
	add	esi, 8
873
	jmp	.next_resendq
1 ha 874
 
907 mikedld 875
  .last_resendq:
876
	popad
1 ha 877
 
907 mikedld 878
    @@: ; Send an ACK to that fin, and enter closewait state
1 ha 879
 
907 mikedld 880
	mov	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
881
	lea	esi, [ebx + SOCKET.RCV_NXT]
882
	mov	eax, [esi]		; save original
883
	call	inc_inet_esi
884
	;; jmp    ste_ack - NO, there may be data
1 ha 885
 
907 mikedld 886
  .check_ack:
887
	; Check that we received an ACK
888
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
889
	jz	.exit
1 ha 890
 
907 mikedld 891
	; TODO - done, I think!
892
	; First, look at the incoming window. If this is less than or equal to 1024,
893
	; Set the socket window timer to 1. This will stop an additional packets being queued.
894
	; ** I may need to tweak this value, since I do not know how many packets are already queued
895
	mov	cx, [edx + 20 + TCP_PACKET.Window]
896
	xchg	cl, ch
897
	cmp	cx, 1024
898
	ja	@f
1 ha 899
 
907 mikedld 900
	mov	[ebx + SOCKET.wndsizeTimer], 1
1 ha 901
 
907 mikedld 902
    @@: ; OK, here is the deal
903
	; My recv.nct field holds the seq of the expected next rec byte
904
	; if the recevied sequence number is not equal to this, do not
905
	; increment the recv.nxt field, do not copy data - just send a
906
	; repeat ack.
1 ha 907
 
907 mikedld 908
	; recv.nxt is in dword [edx+24], in inet format
909
	; recv seq is in [sktAddr]+56, in inet format
910
	; just do a comparision
911
	mov	ecx, [ebx + SOCKET.RCV_NXT]
912
	cmp	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
913
	jne	@f
914
	mov	ecx, eax
1 ha 915
 
907 mikedld 916
    @@: cmp	ecx, [edx + 20 + TCP_PACKET.SequenceNumber]
917
	jne	.ack
1 ha 918
 
919
 
907 mikedld 920
	; Read the data bytes, store in socket buffer
921
	movzx	ecx, [edx + IP_PACKET.TotalLength]
922
	xchg	cl, ch
923
	sub	ecx, 40 		   ; Discard 40 bytes of header
924
	jnz	.data			   ; Read data, if any
1 ha 925
 
907 mikedld 926
	; If we had received a fin, we need to ACK it.
927
	cmp	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
928
	je	.ack
929
	jmp	.exit
1 ha 930
 
907 mikedld 931
  .data:
932
	push	ecx
1 ha 933
 
907 mikedld 934
	add	[ebx + SOCKET.rxDataCount], ecx      ; increment the count of bytes in buffer
1 ha 935
 
907 mikedld 936
	mov	eax, [ebx + SOCKET.PID]       ; get socket owner PID
937
	push	eax
1 ha 938
 
907 mikedld 939
	mov	eax, [ebx + SOCKET.rxDataCount]      ; get # of bytes already in buffer
1 ha 940
 
907 mikedld 941
	; point to the location to store the data
942
	lea	edi, [ebx + eax + SOCKETHEADERSIZE]
943
	sub	edi, ecx
1 ha 944
 
907 mikedld 945
	add	edx, 40        ; edx now points to the data
946
	mov	esi, edx
1 ha 947
 
907 mikedld 948
	cld
949
	rep	movsb	       ; copy the data across
1 ha 950
 
907 mikedld 951
	; flag an event to the application
952
	pop	eax
953
	mov	ecx, 1
954
	mov	esi, TASK_DATA + TASKDATA.pid
1 ha 955
 
907 mikedld 956
  .next_pid:
957
	cmp	[esi], eax
958
	je	.found_pid
959
	inc	ecx
960
	add	esi, 0x20
961
	cmp	ecx, [TASK_COUNT]
962
	jbe	.next_pid
1 ha 963
 
907 mikedld 964
  .found_pid:
965
	shl	ecx, 8
966
	or	[ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
1 ha 967
 
907 mikedld 968
	pop	ecx
1 ha 969
 
907 mikedld 970
	; Update our recv.nxt field
971
	lea	esi, [ebx + SOCKET.RCV_NXT]
972
	call	add_inet_esi
1 ha 973
 
907 mikedld 974
  .ack:
975
	; Send an ACK
976
	; Now construct the response, and queue for sending by IP
977
	mov	eax, EMPTY_QUEUE
978
	call	dequeue
979
	cmp	ax, NO_BUFFER
980
	je	.exit
1 ha 981
 
907 mikedld 982
	push	eax
1 ha 983
 
907 mikedld 984
	mov	bl, TH_ACK
985
	xor	ecx, ecx
986
	xor	esi, esi
987
	stdcall build_tcp_packet, [sockAddr]
1 ha 988
 
907 mikedld 989
	mov	eax, NET1OUT_QUEUE
1 ha 990
 
907 mikedld 991
	mov	edx, [stack_ip]
992
	mov	ecx, [sockAddr]
993
	cmp	edx, [ecx + SOCKET.RemoteIP]
994
	jne	.not_local
995
	mov	eax, IPIN_QUEUE
1 ha 996
 
907 mikedld 997
  .not_local:
998
	; Send it.
999
	pop	ebx
1000
	call	queue
1 ha 1001
 
907 mikedld 1002
  .exit:
1003
	ret
1004
endp
1 ha 1005
 
1006
 
907 mikedld 1007
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
1008
	; We can either receive an ACK of a fin, or a fin
1009
	mov	al, [edx + 20 + TCP_PACKET.Flags]
1010
	and	al, TH_FIN + TH_ACK
1 ha 1011
 
907 mikedld 1012
	cmp	al, TH_ACK
1013
	jne	@f
1 ha 1014
 
907 mikedld 1015
	; It was an ACK
1016
	mov	[ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
1017
	jmp	.exit
1 ha 1018
 
907 mikedld 1019
    @@: mov	[ebx + SOCKET.TCBState], TCB_CLOSING
1020
	cmp	al, TH_FIN
1021
	je	@f
1022
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1023
 
907 mikedld 1024
    @@: lea	esi, [ebx + SOCKET.RCV_NXT]
1025
	call	inc_inet_esi
1 ha 1026
 
907 mikedld 1027
	; Send an ACK
1028
	mov	eax, EMPTY_QUEUE
1029
	call	dequeue
1030
	cmp	ax, NO_BUFFER
1031
	je	.exit
1 ha 1032
 
907 mikedld 1033
	push	eax
1 ha 1034
 
907 mikedld 1035
	mov	bl, TH_ACK
1036
	xor	ecx, ecx
1037
	xor	esi, esi
1038
	stdcall build_tcp_packet, [sockAddr]
1 ha 1039
 
907 mikedld 1040
	mov	eax, NET1OUT_QUEUE
1041
	mov	edx, [stack_ip]
1042
	mov	ecx, [sockAddr]
1043
	cmp	edx, [ecx + SOCKET.RemoteIP]
1044
	jne	.not_local
1045
	mov	eax, IPIN_QUEUE
1 ha 1046
 
907 mikedld 1047
  .not_local:
1048
	; Send it.
1049
	pop	ebx
1050
	call	queue
1 ha 1051
 
907 mikedld 1052
  .exit:
1053
	ret
1054
endp
1 ha 1055
 
1056
 
907 mikedld 1057
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
1058
	test	[edx + 20 + TCP_PACKET.Flags], TH_FIN
1059
	jz	.exit
1 ha 1060
 
907 mikedld 1061
	; Change state, as we have a fin
1062
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1063
 
907 mikedld 1064
	lea	esi, [ebx + SOCKET.RCV_NXT]
1065
	call	inc_inet_esi
1 ha 1066
 
907 mikedld 1067
	; Send an ACK
1068
	mov	eax, EMPTY_QUEUE
1069
	call	dequeue
1070
	cmp	ax, NO_BUFFER
1071
	je	.exit
1 ha 1072
 
907 mikedld 1073
	push	eax
1 ha 1074
 
907 mikedld 1075
	mov	bl, TH_ACK
1076
	xor	ecx, ecx
1077
	xor	esi, esi
1078
	stdcall build_tcp_packet, [sockAddr]
1 ha 1079
 
907 mikedld 1080
	mov	eax, NET1OUT_QUEUE
1081
	mov	edx, [stack_ip]
1082
	mov	ecx, [sockAddr]
1083
	cmp	edx, [ecx + SOCKET.RemoteIP]
1084
	jne	.not_local
1085
	mov	eax, IPIN_QUEUE
1 ha 1086
 
907 mikedld 1087
  .not_local:
1088
	; Send it.
1089
	pop	ebx
1090
	call	queue
1 ha 1091
 
907 mikedld 1092
  .exit:
1093
	ret
1094
endp
1 ha 1095
 
1096
 
907 mikedld 1097
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
1098
	; Intentionally left empty
1099
	; socket_close_tcp handles this
1100
	ret
1101
endp
1 ha 1102
 
1103
 
907 mikedld 1104
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
1105
	; We can either receive an ACK of a fin, or a fin
1106
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
1107
	jz	.exit
1 ha 1108
 
907 mikedld 1109
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1110
 
907 mikedld 1111
  .exit:
1112
	ret
1113
endp
1 ha 1114
 
1115
 
907 mikedld 1116
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
1117
	; Look at control flags - expecting an ACK
1118
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
1119
	jz	.exit
1 ha 1120
 
907 mikedld 1121
	; delete the socket
1122
	stdcall net_socket_free, ebx
1 ha 1123
 
907 mikedld 1124
  .exit:
1125
	ret
1126
endp
1 ha 1127
 
1128
 
907 mikedld 1129
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
1130
	ret
1131
endp
1 ha 1132
 
1133
 
907 mikedld 1134
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
1135
	ret
1136
endp