Subversion Repositories Kolibri OS

Rev

Rev 2130 | Rev 2434 | 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: 2209 $
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
1183 clevermous 45
TCP_TIMEOUT	    equ 	20		; resend if not replied to in x hs
907 mikedld 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
1095 diamond 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
 
1095 diamond 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,,
1183 clevermous 231
	imul	esi, ecx, IPBUFFSIZE
232
	add	esi, resendBuffer
1 ha 233
 
907 mikedld 234
	; we have resend buffer location in esi
235
	mov	ecx, IPBUFFSIZE
1 ha 236
 
907 mikedld 237
	; copy data across
238
	push	edi
239
	cld
240
	rep	movsb
241
	pop	edi
1 ha 242
 
907 mikedld 243
	; queue packet
244
	mov	eax, NET1OUT_QUEUE
245
	mov	edx, [stack_ip]
246
	cmp	edx, [edi + IP_PACKET.DestinationAddress]
247
	jne	.not_local
248
	mov	eax, IPIN_QUEUE
1 ha 249
 
907 mikedld 250
  .not_local:
251
	pop	ebx
252
	call	queue
1 ha 253
 
907 mikedld 254
  .tth005:
255
	popad
1 ha 256
 
907 mikedld 257
	inc	ecx
258
	add	esi, 8
259
	jmp	.next_resendq
1 ha 260
 
907 mikedld 261
  .exit:
262
	ret
263
endp
1 ha 264
 
265
 
266
;***************************************************************************
267
;   Function
268
;      tcp_rx
269
;
270
;   Description
271
;       TCP protocol handler
272
;       This is a kernel function, called by ip_rx
273
;       IP buffer address given in edx
274
;          IP buffer number in eax
275
;          Free up (or re-use) IP buffer when finished
276
;
277
;***************************************************************************
278
 
907 mikedld 279
proc tcp_rx stdcall uses ebx
280
	; The process is as follows.
281
	; Look for a socket with matching remote IP, remote port, local port
282
	; if not found, then
283
	; look for remote IP + local port match ( where sockets remote port = 0)
284
	; if not found, then
285
	; look for a socket where local socket port == IP packets remote port
286
	; where sockets remote port, remote IP = 0
287
	; discard if not found
288
	; Call sockets tcbStateMachine, with pointer to packet.
289
	; the state machine will not delete the packet, so do that here.
1 ha 290
 
907 mikedld 291
	push	eax
1 ha 292
 
907 mikedld 293
	; Look for a socket where
294
	; IP Packet TCP Destination Port = local Port
295
	; IP Packet SA = Remote IP
296
	; IP Packet TCP Source Port = remote Port
1 ha 297
 
907 mikedld 298
	mov	ebx, net_sockets
1 ha 299
 
907 mikedld 300
  .next_socket.1:
301
	mov	ebx, [ebx + SOCKET.NextPtr]
302
	or	ebx, ebx
303
	jz	.next_socket.1.exit
1 ha 304
 
907 mikedld 305
;        DEBUGF  1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
1 ha 306
 
907 mikedld 307
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
308
	cmp	[ebx + SOCKET.LocalPort], ax		; get the dest. port from the TCP hdr
309
	jne	.next_socket.1				; different - try next socket
1 ha 310
 
907 mikedld 311
;        DEBUGF  1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
1 ha 312
 
907 mikedld 313
	mov	eax, [edx + IP_PACKET.SourceAddress]	; get the source IP Addr from the IP hdr
314
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
315
	jne	.next_socket.1				; different - try next socket
1 ha 316
 
907 mikedld 317
;        DEBUGF  1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
1 ha 318
 
907 mikedld 319
	mov	ax, [edx + 20 + TCP_PACKET.SourcePort]	; get the source port from the TCP hdr
320
	cmp	[ebx + SOCKET.RemotePort], ax		; compare with socket's remote port
321
	jne	.next_socket.1				; different - try next socket
1 ha 322
 
907 mikedld 323
	; We have a complete match - use this socket
324
	jmp	.change_state
1 ha 325
 
907 mikedld 326
  .next_socket.1.exit:
1 ha 327
 
907 mikedld 328
	; If we got here, there was no match
329
	; Look for a socket where
330
	; IP Packet TCP Destination Port = local Port
331
	; IP Packet SA = Remote IP
332
	; socket remote Port = 0
1 ha 333
 
907 mikedld 334
	mov	ebx, net_sockets
1 ha 335
 
907 mikedld 336
  .next_socket.2:
337
	mov	ebx, [ebx + SOCKET.NextPtr]
338
	or	ebx, ebx
339
	jz	.next_socket.2.exit
1 ha 340
 
907 mikedld 341
;        DEBUGF  1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
1 ha 342
 
907 mikedld 343
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
344
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
345
	jne	.next_socket.2				; different - try next socket
1 ha 346
 
907 mikedld 347
;        DEBUGF  1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
1 ha 348
 
907 mikedld 349
	mov	eax, [edx + IP_PACKET.SourceAddress]	; get the source IP Addr from the IP hdr
350
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
351
	jne	.next_socket.2				; different - try next socket
1 ha 352
 
907 mikedld 353
;        DEBUGF  1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
1 ha 354
 
907 mikedld 355
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
356
	jne	.next_socket.2				; different - try next socket
1 ha 357
 
907 mikedld 358
	; We have a complete match - use this socket
359
	jmp	.change_state
1 ha 360
 
907 mikedld 361
  .next_socket.2.exit:
1 ha 362
 
907 mikedld 363
	; If we got here, there was no match
364
	; Look for a socket where
365
	; IP Packet TCP Destination Port = local Port
366
	; socket Remote IP = 0
367
	; socket remote Port = 0
1 ha 368
 
907 mikedld 369
	mov	ebx, net_sockets
1 ha 370
 
907 mikedld 371
  .next_socket.3:
372
	mov	ebx, [ebx + SOCKET.NextPtr]
373
	or	ebx, ebx
374
	jz	.next_socket.3.exit
1 ha 375
 
907 mikedld 376
;        DEBUGF  1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
377
 
378
	mov	ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get destination port from the TCP hdr
379
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
380
	jne	.next_socket.3				; different - try next socket
381
 
382
;        DEBUGF  1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
383
 
384
	cmp	[ebx + SOCKET.RemoteIP], 0		; only match a socket remote IP of 0
385
	jne	.next_socket.3				; different - try next socket
386
 
387
;        DEBUGF  1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
388
 
389
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
390
	jne	.next_socket.3				; different - try next socket
391
 
392
	; We have a complete match - use this socket
393
	jmp	.change_state
394
 
395
  .next_socket.3.exit:
396
 
397
	; If we got here, we need to reject the packet
398
 
399
	DEBUGF	1, "K : tcp_rx - dumped\n"
400
	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 401
 
907 mikedld 402
	inc	[dumped_rx_count]
403
	jmp	.exit
404
 
405
  .change_state:
406
 
407
	; We have a valid socket/TCB, so call the TCB State Machine for that skt.
408
	; socket is pointed to by ebx
409
	; IP packet is pointed to by edx
410
	; IP buffer number is on stack ( it will be popped at the end)
411
 
412
	stdcall tcpStateMachine, ebx
413
 
414
  .exit:
415
	pop	eax
416
	call	freeBuff
417
	ret
418
endp
419
 
420
 
1 ha 421
;***************************************************************************
422
;   Function
423
;      buildTCPPacket
424
;
425
;   Description
426
;       builds an IP Packet with TCP data fully populated for transmission
427
;       You may destroy any and all registers
428
;          TCP control flags specified in bl
429
;          This TCB is in [sktAddr]
430
;          User data pointed to by esi
431
;       Data length in ecx
432
;          Transmit buffer number in eax
433
;
434
;***************************************************************************
435
 
907 mikedld 436
proc build_tcp_packet stdcall, sockAddr:DWORD
437
	push	ecx			   ; Save data length
1 ha 438
 
907 mikedld 439
	; convert buffer pointer eax to the absolute address
440
	mov	ecx, IPBUFFSIZE
441
	mul	ecx
442
	add	eax, IPbuffs
1 ha 443
 
907 mikedld 444
	mov	edx, eax
1 ha 445
 
907 mikedld 446
	mov	[edx + 20 + TCP_PACKET.Flags], bl		; TCP flags
1 ha 447
 
907 mikedld 448
	mov	ebx, [sockAddr]
1 ha 449
 
907 mikedld 450
	; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
1 ha 451
 
907 mikedld 452
	; Fill in the IP header ( some data is in the socket descriptor)
453
	mov	eax, [ebx + SOCKET.LocalIP]
454
	mov	[edx + IP_PACKET.SourceAddress], eax
455
	mov	eax, [ebx + SOCKET.RemoteIP]
456
	mov	[edx + IP_PACKET.DestinationAddress], eax
1 ha 457
 
907 mikedld 458
	mov	[edx + IP_PACKET.VersionAndIHL], 0x45
459
	mov	[edx + IP_PACKET.TypeOfService], 0
1 ha 460
 
907 mikedld 461
	pop	eax		      ; Get the TCP data length
462
	push	eax
1 ha 463
 
907 mikedld 464
	add	eax, 20 + 20	       ; add IP header and TCP header lengths
465
	rol	ax, 8
466
	mov	[edx + IP_PACKET.TotalLength], ax
467
	mov	[edx + IP_PACKET.Identification], 0
468
	mov	[edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
469
	mov	[edx + IP_PACKET.TimeToLive], 0x20
470
	mov	[edx + IP_PACKET.Protocol], PROTOCOL_TCP
1 ha 471
 
907 mikedld 472
	; Checksum left unfilled
473
	mov	[edx + IP_PACKET.HeaderChecksum], 0
1 ha 474
 
907 mikedld 475
	; Fill in the TCP header (some data is in the socket descriptor)
476
	mov	ax, [ebx + SOCKET.LocalPort]
477
	mov	[edx + 20 + TCP_PACKET.SourcePort], ax		; Local Port
1 ha 478
 
907 mikedld 479
	mov	ax, [ebx + SOCKET.RemotePort]
480
	mov	[edx + 20 + TCP_PACKET.DestinationPort], ax	; desitination Port
1 ha 481
 
907 mikedld 482
	; Checksum left unfilled
483
	mov	[edx + 20 + TCP_PACKET.Checksum], 0
1 ha 484
 
907 mikedld 485
	; sequence number
486
	mov	eax, [ebx + SOCKET.SND_NXT]
487
	mov	[edx + 20 + TCP_PACKET.SequenceNumber], eax
1 ha 488
 
907 mikedld 489
	; ack number
490
	mov	eax, [ebx + SOCKET.RCV_NXT]
491
	mov	[edx + 20 + TCP_PACKET.AckNumber], eax
1 ha 492
 
907 mikedld 493
	; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
494
	; 768 bytes seems better
495
	mov	[edx + 20 + TCP_PACKET.Window], 0x0003
1 ha 496
 
907 mikedld 497
	; Urgent pointer (0)
498
	mov	[edx + 20 + TCP_PACKET.UrgentPointer], 0
1 ha 499
 
907 mikedld 500
	; data offset ( 0x50 )
501
	mov	[edx + 20 + TCP_PACKET.DataOffset], 0x50
1 ha 502
 
907 mikedld 503
	pop	ecx		     ; count of bytes to send
504
	mov	ebx, ecx	    ; need the length later
1 ha 505
 
907 mikedld 506
	cmp	ebx, 0
507
	jz	@f
1 ha 508
 
907 mikedld 509
	mov	edi, edx
510
	add	edi, 40
511
	cld
512
	rep	movsb		    ; copy the data across
1 ha 513
 
907 mikedld 514
    @@: ; we have edx as IPbuffer ptr.
515
	; Fill in the TCP checksum
516
	; First, fill in pseudoheader
517
	mov	eax, [edx + IP_PACKET.SourceAddress]
518
	mov	[pseudoHeader], eax
519
	mov	eax, [edx + IP_PACKET.DestinationAddress]
520
	mov	[pseudoHeader + 4], eax
521
	mov	word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
522
	add	ebx, 20
523
	mov	[pseudoHeader + 10], bh
524
	mov	[pseudoHeader + 11], bl
1 ha 525
 
907 mikedld 526
	mov	eax, pseudoHeader
527
	mov	[checkAdd1], eax
528
	mov	word[checkSize1], 12
529
	mov	eax, edx
530
	add	eax, 20
531
	mov	[checkAdd2], eax
532
	mov	eax, ebx
533
	mov	[checkSize2], ax
1 ha 534
 
907 mikedld 535
	call	checksum
1 ha 536
 
907 mikedld 537
	; store it in the TCP checksum ( in the correct order! )
538
	mov	ax, [checkResult]
539
	rol	ax, 8
540
	mov	[edx + 20 + TCP_PACKET.Checksum], ax
1 ha 541
 
907 mikedld 542
	; Fill in the IP header checksum
543
	GET_IHL eax, edx	       ; get IP-Header length
544
	stdcall checksum_jb, edx, eax  ; buf_ptr, buf_size
545
	rol	ax, 8
546
	mov	[edx + IP_PACKET.HeaderChecksum], ax
1 ha 547
 
907 mikedld 548
	ret
549
endp
1 ha 550
 
551
 
552
; Increments the 32 bit value pointed to by esi in internet order
907 mikedld 553
proc inc_inet_esi stdcall
554
	push	eax
555
	mov	eax, [esi]
556
	bswap	eax
557
	inc	eax
558
	bswap	eax
559
	mov	[esi], eax
560
	pop	eax
561
	ret
562
endp
1 ha 563
 
564
 
565
; Increments the 32 bit value pointed to by esi in internet order
566
; by the value in ecx
907 mikedld 567
proc add_inet_esi stdcall
568
	push	eax
569
	mov	eax, [esi]
570
	bswap	eax
571
	add	eax, ecx
572
	bswap	eax
573
	mov	[esi], eax
574
	pop	eax
575
	ret
576
endp
1 ha 577
 
578
 
579
iglobal
907 mikedld 580
  TCBStateHandler dd \
581
    stateTCB_LISTEN, \
582
    stateTCB_SYN_SENT, \
583
    stateTCB_SYN_RECEIVED, \
584
    stateTCB_ESTABLISHED, \
585
    stateTCB_FIN_WAIT_1, \
586
    stateTCB_FIN_WAIT_2, \
587
    stateTCB_CLOSE_WAIT, \
588
    stateTCB_CLOSING, \
589
    stateTCB_LAST_ACK, \
590
    stateTCB_TIME_WAIT, \
591
    stateTCB_CLOSED
1 ha 592
endg
593
 
907 mikedld 594
 
1 ha 595
;***************************************************************************
596
;   Function
597
;      tcpStateMachine
598
;
599
;   Description
600
;       TCP state machine
601
;       This is a kernel function, called by tcp_rx
602
;
603
;       IP buffer address given in edx
907 mikedld 604
;          Socket/TCB address in ebx
1 ha 605
;
606
;       The IP buffer will be released by the caller
607
;***************************************************************************
608
 
907 mikedld 609
proc tcpStateMachine stdcall, sockAddr:DWORD
610
	; as a packet has been received, update the TCB timer
611
	mov	[ebx + SOCKET.TCBTimer], TWOMSL
1 ha 612
 
907 mikedld 613
	; If the received packet has an ACK bit set,
614
	; remove any packets in the resend queue that this
615
	; received packet acknowledges
616
	pushad
617
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
618
	jz	.call_handler					; No ACK, so no data yet
1 ha 619
 
907 mikedld 620
	; get skt number in eax
621
	stdcall net_socket_addr_to_num, ebx
1 ha 622
 
907 mikedld 623
	; The ack number is in [edx + 28], inet format
624
	; skt in eax
1 ha 625
 
907 mikedld 626
	mov	esi, resendQ
627
	xor	ecx, ecx
1 ha 628
 
907 mikedld 629
  .next_resendq:
630
	cmp	ecx, NUMRESENDENTRIES
631
	je	.call_handler	  ; None left
632
	cmp	[esi + 4], eax
633
	je	@f		  ; found one
634
	inc	ecx
635
	add	esi, 8
636
	jmp	.next_resendq
1 ha 637
 
907 mikedld 638
    @@: 		  ; Can we delete this buffer?
1 ha 639
 
907 mikedld 640
			  ; If yes, goto @@. No, goto .next_resendq
641
	; Get packet data address
1 ha 642
 
907 mikedld 643
	push	ecx
644
	; Now get buffer location, and copy buffer across. argh! more copying,,
645
	imul	edi, ecx, IPBUFFSIZE
646
	add	edi, resendBuffer
1 ha 647
 
907 mikedld 648
	; we have dest buffer location in edi. incoming packet in edx.
649
	; Get this packets sequence number
650
	; preserve al, ecx, esi, edx
651
	mov	ecx, [edi + 20 + TCP_PACKET.SequenceNumber]
652
	bswap	ecx
653
	movzx	ebx, word[edi + 2]
654
	xchg	bl, bh
655
	sub	ebx, 40
656
	add	ecx, ebx	  ; ecx is now seq# of last byte +1, intel format
1 ha 657
 
907 mikedld 658
	; get recievd ack #, in intel format
659
	mov	ebx, [edx + 20 + TCP_PACKET.AckNumber]
660
	bswap	ebx
1 ha 661
 
907 mikedld 662
	cmp	ebx, ecx	; Finally. ecx = rx'ed ack. ebx = last byte in que
663
				; DANGER! need to handle case that we have just
664
				; passed the 2**32, and wrapped round!
665
	pop	ecx
666
	jae	@f		; if rx > old, delete old
1 ha 667
 
907 mikedld 668
	inc	ecx
669
	add	esi, 8
670
	jmp	.next_resendq
1 ha 671
 
907 mikedld 672
    @@: mov	dword[esi + 4], 0
673
	inc	ecx
674
	add	esi, 8
675
	jmp	.next_resendq
1 ha 676
 
907 mikedld 677
  .call_handler:
678
	popad
1 ha 679
 
907 mikedld 680
	; Call handler for given TCB state
1 ha 681
 
907 mikedld 682
	mov	eax, [ebx + SOCKET.TCBState]
683
	cmp	eax, TCB_LISTEN
684
	jb	.exit
685
	cmp	eax, TCB_CLOSED
686
	ja	.exit
1 ha 687
 
907 mikedld 688
	stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
1 ha 689
 
907 mikedld 690
  .exit:
691
	ret
692
endp
1 ha 693
 
1181 clevermous 694
;***************************************************************************
695
;   Function
696
;      signal_network_event
697
;
698
;   Description
699
;       Signals about network event to socket owner
700
;       This is a kernel function, called from TCP handler
701
;
702
;          Socket/TCB address in ebx
703
;***************************************************************************
704
proc signal_network_event
705
	push	ecx esi eax
706
	mov	eax, [ebx + SOCKET.PID]
707
	mov	ecx, 1
708
	mov	esi, TASK_DATA + TASKDATA.pid
1 ha 709
 
1181 clevermous 710
  .next_pid:
711
	cmp	[esi], eax
712
	je	.found_pid
713
	inc	ecx
714
	add	esi, 0x20
715
	cmp	ecx, [TASK_COUNT]
716
	jbe	.next_pid
717
 
718
  .found_pid:
719
	shl	ecx, 8
720
	or	[ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
721
	pop	eax esi ecx
722
	ret
723
endp
724
 
907 mikedld 725
proc stateTCB_LISTEN stdcall, sockAddr:DWORD
726
	; In this case, we are expecting a SYN packet
727
	; For now, if the packet is a SYN, process it, and send a response
728
	; If not, ignore it
1 ha 729
 
907 mikedld 730
	; Look at control flags
731
	test	[edx + 20 + TCP_PACKET.Flags], TH_SYN
732
	jz	.exit
1 ha 733
 
907 mikedld 734
	; We have a SYN. update the socket with this IP packets details,
735
	; And send a response
1 ha 736
 
907 mikedld 737
	mov	eax, [edx + IP_PACKET.SourceAddress]
738
	mov	[ebx + SOCKET.RemoteIP], eax
739
	mov	ax, [edx + 20 + TCP_PACKET.SourcePort]
740
	mov	[ebx + SOCKET.RemotePort], ax
741
	mov	eax, [edx + 20 + TCP_PACKET.SequenceNumber]
742
	mov	[ebx + SOCKET.IRS], eax
743
	mov	[ebx + SOCKET.RCV_NXT], eax
744
	lea	esi, [ebx + SOCKET.RCV_NXT]
745
	call	inc_inet_esi ; RCV.NXT
746
	mov	eax, [ebx + SOCKET.ISS]
747
	mov	[ebx + SOCKET.SND_NXT], eax
1 ha 748
 
907 mikedld 749
	; Now construct the response, and queue for sending by IP
750
	mov	eax, EMPTY_QUEUE
751
	call	dequeue
752
	cmp	ax, NO_BUFFER
753
	je	.exit
1 ha 754
 
1181 clevermous 755
	push	ebx
907 mikedld 756
	push	eax
757
	mov	bl, TH_SYN + TH_ACK
758
	xor	ecx, ecx
759
	xor	esi, esi
760
	stdcall build_tcp_packet, [sockAddr]
1 ha 761
 
907 mikedld 762
	mov	eax, NET1OUT_QUEUE
763
	mov	edx, [stack_ip]
764
	mov	ecx, [sockAddr]
765
	cmp	edx, [ecx + SOCKET.RemoteIP]
766
	jne	.not_local
767
	mov	eax, IPIN_QUEUE
1 ha 768
 
907 mikedld 769
  .not_local:
770
	; Send it.
771
	pop	ebx
772
	call	queue
1 ha 773
 
1181 clevermous 774
	pop	ebx
907 mikedld 775
	mov	esi, [sockAddr]
776
	mov	[esi + SOCKET.TCBState], TCB_SYN_RECEIVED
1181 clevermous 777
	call	signal_network_event
1 ha 778
 
907 mikedld 779
	; increment SND.NXT in socket
780
	add	esi, SOCKET.SND_NXT
781
	call	inc_inet_esi
1 ha 782
 
907 mikedld 783
  .exit:
784
	ret
785
endp
1 ha 786
 
787
 
907 mikedld 788
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
789
	; We are awaiting an ACK to our SYN, with a SYM
790
	; Look at control flags - expecting an ACK
1 ha 791
 
907 mikedld 792
	mov	al, [edx + 20 + TCP_PACKET.Flags]
793
	and	al, TH_SYN + TH_ACK
794
	cmp	al, TH_SYN + TH_ACK
795
	je	.syn_ack
1 ha 796
 
907 mikedld 797
	test	al, TH_SYN
798
	jz	.exit
1 ha 799
 
907 mikedld 800
	mov	[ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
801
	push	TH_SYN + TH_ACK
802
	jmp	.send
1 ha 803
 
907 mikedld 804
  .syn_ack:
805
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
806
	push	TH_ACK
1 ha 807
 
907 mikedld 808
  .send:
1181 clevermous 809
	call	signal_network_event
907 mikedld 810
	; Store the recv.nxt field
811
	mov	eax, [edx + 20 + TCP_PACKET.SequenceNumber]
1 ha 812
 
907 mikedld 813
	; Update our recv.nxt field
814
	mov	[ebx + SOCKET.RCV_NXT], eax
815
	lea	esi, [ebx + SOCKET.RCV_NXT]
816
	call	inc_inet_esi
1 ha 817
 
907 mikedld 818
	; Send an ACK
819
	; Now construct the response, and queue for sending by IP
820
	mov	eax, EMPTY_QUEUE
821
	call	dequeue
822
	cmp	ax, NO_BUFFER
823
	pop	ebx
824
	je	.exit
1 ha 825
 
907 mikedld 826
	push	eax
1 ha 827
 
907 mikedld 828
	xor	ecx, ecx
829
	xor	esi, esi
830
	stdcall build_tcp_packet, [sockAddr]
1 ha 831
 
907 mikedld 832
	mov	eax, NET1OUT_QUEUE
833
	mov	edx, [stack_ip]
834
	mov	ecx, [sockAddr]
835
	cmp	edx, [ecx + SOCKET.RemoteIP]
836
	jne	.not_local
837
	mov	eax, IPIN_QUEUE
1 ha 838
 
907 mikedld 839
  .not_local:
840
	; Send it.
841
	pop	ebx
842
	call	queue
1 ha 843
 
907 mikedld 844
  .exit:
845
	ret
846
endp
1 ha 847
 
848
 
907 mikedld 849
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
850
	; In this case, we are expecting an ACK packet
851
	; For now, if the packet is an ACK, process it,
852
	; If not, ignore it
1 ha 853
 
922 mikedld 854
	test	[edx + 20 + TCP_PACKET.Flags], TH_RST
855
	jz	.check_ack
1 ha 856
 
907 mikedld 857
	push	[ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
858
	pop	[ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
1 ha 859
 
922 mikedld 860
	mov	[ebx + SOCKET.TCBState], TCB_LISTEN
1181 clevermous 861
	jmp	.signal
1 ha 862
 
922 mikedld 863
  .check_ack:
907 mikedld 864
	; Look at control flags - expecting an ACK
865
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
866
	jz	.exit
1 ha 867
 
907 mikedld 868
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
1181 clevermous 869
  .signal:
870
	call	signal_network_event
1 ha 871
 
907 mikedld 872
  .exit:
873
	ret
874
endp
1 ha 875
 
876
 
907 mikedld 877
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
878
	; Here we are expecting data, or a request to close
879
	; OR both...
1 ha 880
 
1181 clevermous 881
	; Ignore all packets with sequnce number other than next expected
882
 
883
	; recv.nxt is in dword [edx+24], in inet format
884
	; recv seq is in [sktAddr]+56, in inet format
885
	; just do a comparision
886
	mov	eax, [ebx + SOCKET.RCV_NXT]
887
	cmp	eax, [edx + 20 + TCP_PACKET.SequenceNumber]
888
	jne	.exit
889
 
907 mikedld 890
	; Did we receive a FIN or RST?
1288 tsdima 891
	test	[edx + 20 + TCP_PACKET.Flags], TH_FIN+TH_RST
922 mikedld 892
	jz	.check_ack
1 ha 893
 
907 mikedld 894
	; It was a fin or reset.
1 ha 895
 
907 mikedld 896
	; Remove resend entries from the queue  - I dont want to send any more data
897
	pushad
1 ha 898
 
907 mikedld 899
	; get skt #
900
	stdcall net_socket_addr_to_num, ebx
1 ha 901
 
907 mikedld 902
	mov	esi, resendQ
903
	mov	ecx, 0
1 ha 904
 
907 mikedld 905
  .next_resendq:
906
	cmp	ecx, NUMRESENDENTRIES
907
	je	.last_resendq	    ; None left
908
	cmp	[esi + 4], eax
909
	je	@f		    ; found one
910
	inc	ecx
911
	add	esi, 8
912
	jmp	.next_resendq
1 ha 913
 
907 mikedld 914
    @@: mov	dword[esi + 4], 0
915
	inc	ecx
916
	add	esi, 8
917
	jmp	.next_resendq
1 ha 918
 
907 mikedld 919
  .last_resendq:
920
	popad
1 ha 921
 
907 mikedld 922
    @@: ; Send an ACK to that fin, and enter closewait state
1 ha 923
 
907 mikedld 924
	mov	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
1288 tsdima 925
	test	[edx + 20 + TCP_PACKET.Flags], TH_RST
926
	je      @f
927
	mov	[ebx + SOCKET.TCBState], TCB_CLOSED
928
    @@:
1181 clevermous 929
	call	signal_network_event
907 mikedld 930
	lea	esi, [ebx + SOCKET.RCV_NXT]
931
	mov	eax, [esi]		; save original
932
	call	inc_inet_esi
933
	;; jmp    ste_ack - NO, there may be data
1 ha 934
 
907 mikedld 935
  .check_ack:
936
	; Check that we received an ACK
937
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
938
	jz	.exit
1 ha 939
 
907 mikedld 940
	; TODO - done, I think!
941
	; First, look at the incoming window. If this is less than or equal to 1024,
942
	; Set the socket window timer to 1. This will stop an additional packets being queued.
943
	; ** I may need to tweak this value, since I do not know how many packets are already queued
944
	mov	cx, [edx + 20 + TCP_PACKET.Window]
945
	xchg	cl, ch
946
	cmp	cx, 1024
947
	ja	@f
1 ha 948
 
907 mikedld 949
	mov	[ebx + SOCKET.wndsizeTimer], 1
1 ha 950
 
907 mikedld 951
    @@: ; OK, here is the deal
1 ha 952
 
953
 
907 mikedld 954
	; Read the data bytes, store in socket buffer
955
	movzx	ecx, [edx + IP_PACKET.TotalLength]
956
	xchg	cl, ch
957
	sub	ecx, 40 		   ; Discard 40 bytes of header
1019 diamond 958
	ja	.data			   ; Read data, if any
1 ha 959
 
907 mikedld 960
	; If we had received a fin, we need to ACK it.
961
	cmp	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
962
	je	.ack
963
	jmp	.exit
1 ha 964
 
907 mikedld 965
  .data:
2130 serge 966
    push    ecx
2209 Serge 967
	push    ecx edx
2130 serge 968
    lea     ecx, [ebx+SOCKET.lock]
969
    call    mutex_lock
2209 Serge 970
        pop     edx ecx
1019 diamond 971
 
1181 clevermous 972
	push	ebx
1019 diamond 973
	mov	eax, [ebx + SOCKET.rxDataCount]
974
	add	eax, ecx
975
	cmp	eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE
976
	ja	.overflow
1 ha 977
 
1019 diamond 978
	mov	[ebx + SOCKET.rxDataCount], eax      ; increment the count of bytes in buffer
1 ha 979
 
907 mikedld 980
	; point to the location to store the data
981
	lea	edi, [ebx + eax + SOCKETHEADERSIZE]
982
	sub	edi, ecx
1 ha 983
 
907 mikedld 984
	add	edx, 40        ; edx now points to the data
985
	mov	esi, edx
1 ha 986
 
907 mikedld 987
	cld
988
	rep	movsb	       ; copy the data across
1 ha 989
 
2130 serge 990
    lea ecx,[ebx + SOCKET.lock]
991
    call mutex_unlock
992
 
907 mikedld 993
	; flag an event to the application
1181 clevermous 994
	pop	ebx
995
	call	signal_network_event
1 ha 996
 
907 mikedld 997
	pop	ecx
1 ha 998
 
907 mikedld 999
	; Update our recv.nxt field
1000
	lea	esi, [ebx + SOCKET.RCV_NXT]
1001
	call	add_inet_esi
1 ha 1002
 
907 mikedld 1003
  .ack:
1004
	; Send an ACK
1005
	; Now construct the response, and queue for sending by IP
1006
	mov	eax, EMPTY_QUEUE
1007
	call	dequeue
1008
	cmp	ax, NO_BUFFER
1009
	je	.exit
1 ha 1010
 
907 mikedld 1011
	push	eax
1 ha 1012
 
907 mikedld 1013
	mov	bl, TH_ACK
1014
	xor	ecx, ecx
1015
	xor	esi, esi
1016
	stdcall build_tcp_packet, [sockAddr]
1 ha 1017
 
907 mikedld 1018
	mov	eax, NET1OUT_QUEUE
1 ha 1019
 
907 mikedld 1020
	mov	edx, [stack_ip]
1021
	mov	ecx, [sockAddr]
1022
	cmp	edx, [ecx + SOCKET.RemoteIP]
1023
	jne	.not_local
1024
	mov	eax, IPIN_QUEUE
1 ha 1025
 
907 mikedld 1026
  .not_local:
1027
	; Send it.
1028
	pop	ebx
1029
	call	queue
1 ha 1030
 
907 mikedld 1031
  .exit:
1032
	ret
1019 diamond 1033
  .overflow:
1034
	; no place in buffer
1035
	; so simply restore stack and exit
2130 serge 1036
    lea ecx, [ebx + SOCKET.lock]
1037
    call mutex_unlock
1019 diamond 1038
	pop	eax ecx
1039
	ret
907 mikedld 1040
endp
1 ha 1041
 
1042
 
907 mikedld 1043
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
1044
	; We can either receive an ACK of a fin, or a fin
1045
	mov	al, [edx + 20 + TCP_PACKET.Flags]
1046
	and	al, TH_FIN + TH_ACK
1 ha 1047
 
907 mikedld 1048
	cmp	al, TH_ACK
1049
	jne	@f
1 ha 1050
 
907 mikedld 1051
	; It was an ACK
1052
	mov	[ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
1053
	jmp	.exit
1 ha 1054
 
907 mikedld 1055
    @@: mov	[ebx + SOCKET.TCBState], TCB_CLOSING
1056
	cmp	al, TH_FIN
1057
	je	@f
1058
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1059
 
907 mikedld 1060
    @@: lea	esi, [ebx + SOCKET.RCV_NXT]
1061
	call	inc_inet_esi
1 ha 1062
 
907 mikedld 1063
	; Send an ACK
1064
	mov	eax, EMPTY_QUEUE
1065
	call	dequeue
1066
	cmp	ax, NO_BUFFER
1067
	je	.exit
1 ha 1068
 
907 mikedld 1069
	push	eax
1 ha 1070
 
907 mikedld 1071
	mov	bl, TH_ACK
1072
	xor	ecx, ecx
1073
	xor	esi, esi
1074
	stdcall build_tcp_packet, [sockAddr]
1 ha 1075
 
907 mikedld 1076
	mov	eax, NET1OUT_QUEUE
1077
	mov	edx, [stack_ip]
1078
	mov	ecx, [sockAddr]
1079
	cmp	edx, [ecx + SOCKET.RemoteIP]
1080
	jne	.not_local
1081
	mov	eax, IPIN_QUEUE
1 ha 1082
 
907 mikedld 1083
  .not_local:
1084
	; Send it.
1085
	pop	ebx
1086
	call	queue
1 ha 1087
 
907 mikedld 1088
  .exit:
1089
	ret
1090
endp
1 ha 1091
 
1092
 
907 mikedld 1093
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
1094
	test	[edx + 20 + TCP_PACKET.Flags], TH_FIN
1095
	jz	.exit
1 ha 1096
 
907 mikedld 1097
	; Change state, as we have a fin
1098
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1099
 
907 mikedld 1100
	lea	esi, [ebx + SOCKET.RCV_NXT]
1101
	call	inc_inet_esi
1 ha 1102
 
907 mikedld 1103
	; Send an ACK
1104
	mov	eax, EMPTY_QUEUE
1105
	call	dequeue
1106
	cmp	ax, NO_BUFFER
1107
	je	.exit
1 ha 1108
 
907 mikedld 1109
	push	eax
1 ha 1110
 
907 mikedld 1111
	mov	bl, TH_ACK
1112
	xor	ecx, ecx
1113
	xor	esi, esi
1114
	stdcall build_tcp_packet, [sockAddr]
1 ha 1115
 
907 mikedld 1116
	mov	eax, NET1OUT_QUEUE
1117
	mov	edx, [stack_ip]
1118
	mov	ecx, [sockAddr]
1119
	cmp	edx, [ecx + SOCKET.RemoteIP]
1120
	jne	.not_local
1121
	mov	eax, IPIN_QUEUE
1 ha 1122
 
907 mikedld 1123
  .not_local:
1124
	; Send it.
1125
	pop	ebx
1126
	call	queue
1 ha 1127
 
907 mikedld 1128
  .exit:
1129
	ret
1130
endp
1 ha 1131
 
1132
 
907 mikedld 1133
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
1134
	; Intentionally left empty
1135
	; socket_close_tcp handles this
1136
	ret
1137
endp
1 ha 1138
 
1139
 
907 mikedld 1140
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
1141
	; We can either receive an ACK of a fin, or a fin
1142
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
1143
	jz	.exit
1 ha 1144
 
907 mikedld 1145
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1 ha 1146
 
907 mikedld 1147
  .exit:
1148
	ret
1149
endp
1 ha 1150
 
1151
 
907 mikedld 1152
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
1153
	; Look at control flags - expecting an ACK
1154
	test	[edx + 20 + TCP_PACKET.Flags], TH_ACK
1155
	jz	.exit
1 ha 1156
 
907 mikedld 1157
	; delete the socket
1158
	stdcall net_socket_free, ebx
1 ha 1159
 
907 mikedld 1160
  .exit:
1161
	ret
1162
endp
1 ha 1163
 
1164
 
907 mikedld 1165
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
1166
	ret
1167
endp
1 ha 1168
 
1169
 
907 mikedld 1170
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
1171
	ret
1172
endp