Subversion Repositories Kolibri OS

Rev

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

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