Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1196 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
1514 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved.    ;;
1196 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  TCP.INC                                                        ;;
7
;;                                                                 ;;
8
;;  Part of the tcp/ip network stack for KolibriOS                 ;;
9
;;                                                                 ;;
1514 hidnplayr 10
;;   Written by hidnplayr@kolibrios.org                            ;;
1196 hidnplayr 11
;;                                                                 ;;
1514 hidnplayr 12
;;    Based on the code of 4.4BSD                                  ;;
13
;;                                                                 ;;
1196 hidnplayr 14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
15
;;             Version 2, June 1991                                ;;
16
;;                                                                 ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1159 hidnplayr 18
 
1206 hidnplayr 19
$Revision: 1719 $
1159 hidnplayr 20
 
1514 hidnplayr 21
; Socket states
22
TCB_CLOSED		equ 0
23
TCB_LISTEN		equ 1
24
TCB_SYN_SENT		equ 2
25
TCB_SYN_RECEIVED	equ 3
26
TCB_ESTABLISHED 	equ 4
27
TCB_CLOSE_WAIT		equ 5
28
TCB_FIN_WAIT_1		equ 6
29
TCB_CLOSING		equ 7
30
TCB_LAST_ACK		equ 8
31
TCB_FIN_WAIT_2		equ 9
32
TCB_TIMED_WAIT		equ 10
1196 hidnplayr 33
 
1514 hidnplayr 34
; Socket Flags
35
TF_ACKNOW		equ 1 shl 0	; ack peer immediately
36
TF_DELACK		equ 1 shl 1	; ack, but try to delay it
37
TF_NODELAY		equ 1 shl 2	; don't delay packets to coalesce
38
TF_NOOPT		equ 1 shl 3	; don't use tcp options
39
TF_SENTFIN		equ 1 shl 4	; have sent FIN
40
TF_REQ_SCALE		equ 1 shl 5	; have/will request window scaling
41
TF_RCVD_SCALE		equ 1 shl 6	; other side has requested scaling
42
TF_REQ_TSTMP		equ 1 shl 7	; have/will request timestamps
43
TF_RCVD_TSTMP		equ 1 shl 8	; a timestamp was received in SYN
44
TF_SACK_PERMIT		equ 1 shl 9	; other side said I could SACK
1249 hidnplayr 45
 
1514 hidnplayr 46
; Segment flags
47
TH_FIN			equ 1 shl 0
48
TH_SYN			equ 1 shl 1
49
TH_RST			equ 1 shl 2
50
TH_PUSH 		equ 1 shl 3
51
TH_ACK			equ 1 shl 4
52
TH_URG			equ 1 shl 5
1318 hidnplayr 53
 
1514 hidnplayr 54
; Segment header options
55
TCP_OPT_EOL		equ 0		; End of option list.
56
TCP_OPT_NOP		equ 1		; No-Operation.
57
TCP_OPT_MAXSEG		equ 2		; Maximum Segment Size.
58
TCP_OPT_WINDOW		equ 3		; window scale
59
TCP_OPT_TIMESTAMP	equ 8
60
 
1519 hidnplayr 61
; Fundamental timer values
62
TCP_time_MSL		equ 47		; max segment lifetime (30s)
63
TCP_time_re_min 	equ 2		; min retransmission (1,28s)
64
TCP_time_re_max 	equ 100 	; max retransmission (64s)
65
TCP_time_pers_min	equ 8		; min persist (5,12s)
66
TCP_time_pers_max	equ 94		; max persist (60,16s)
67
TCP_time_keep_init	equ 118 	; connectione stablishment (75,52s)
68
TCP_time_keep_idle	equ 4608	; idle time before 1st probe (2h)
69
TCP_time_keep_interval	equ 118 	; between probes when no response (75,52s)
70
TCP_time_rtt_default	equ 5		; default Round Trip Time (3,2s)
71
 
72
; timer constants
73
TCP_max_rxtshift	equ 12		; max retransmissions waiting for ACK
74
TCP_max_keepcnt 	equ 8		; max keepalive probes
75
 
1529 hidnplayr 76
;
77
TCP_max_winshift	equ 14
78
TCP_max_win		equ 65535
1519 hidnplayr 79
 
1514 hidnplayr 80
struct	TCP_segment
1159 hidnplayr 81
	.SourcePort		dw ?
82
	.DestinationPort	dw ?
83
	.SequenceNumber 	dd ?
84
	.AckNumber		dd ?
1196 hidnplayr 85
	.DataOffset		db ?	; DataOffset[0-3 bits] and Reserved[4-7]
86
	.Flags			db ?	; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
1159 hidnplayr 87
	.Window 		dw ?
88
	.Checksum		dw ?
89
	.UrgentPointer		dw ?
1514 hidnplayr 90
	.Data:				; ..or options
1159 hidnplayr 91
ends
92
 
1196 hidnplayr 93
align 4
94
uglobal
1514 hidnplayr 95
	TCP_segments_tx 	rd IP_MAX_INTERFACES
96
	TCP_segments_rx 	rd IP_MAX_INTERFACES
97
	TCP_bytes_rx		rq IP_MAX_INTERFACES
98
	TCP_bytes_tx		rq IP_MAX_INTERFACES
99
	TCP_sequence_num	dd ?
1196 hidnplayr 100
endg
101
 
102
 
103
;-----------------------------------------------------------------
104
;
105
; TCP_init
106
;
107
;  This function resets all TCP variables
108
;
109
;-----------------------------------------------------------------
1529 hidnplayr 110
macro	TCP_init {
1196 hidnplayr 111
 
112
	xor	eax, eax
1514 hidnplayr 113
	mov	edi, TCP_segments_tx
114
	mov	ecx, (6*IP_MAX_INTERFACES)
1196 hidnplayr 115
	rep	stosd
116
 
1529 hidnplayr 117
	pseudo_random	eax
118
	mov	[TCP_sequence_num], eax
1196 hidnplayr 119
 
1529 hidnplayr 120
}
1196 hidnplayr 121
 
122
 
1519 hidnplayr 123
;----------------------
1196 hidnplayr 124
;
1159 hidnplayr 125
;
1519 hidnplayr 126
;----------------------
1529 hidnplayr 127
macro	TCP_timer_160ms {
1159 hidnplayr 128
 
1529 hidnplayr 129
local	.loop
130
local	.exit
131
 
1514 hidnplayr 132
	mov	eax, net_sockets
133
  .loop:
134
	mov	eax, [eax + SOCKET.NextPtr]
135
	or	eax, eax
1159 hidnplayr 136
	jz	.exit
137
 
1542 hidnplayr 138
	cmp	[eax + SOCKET.Protocol], IP_PROTO_TCP		;;; We should also check if family is AF_INET
1514 hidnplayr 139
	jne	.loop
1249 hidnplayr 140
 
1519 hidnplayr 141
	dec	[eax + TCP_SOCKET.timer_ack]
1514 hidnplayr 142
	jnz	.loop
1159 hidnplayr 143
 
1519 hidnplayr 144
	DEBUGF	1,"TCP ack for socket %x expired, time to piggyback!\n", eax
1159 hidnplayr 145
 
1519 hidnplayr 146
	push	eax
1529 hidnplayr 147
	call	TCP_respond_socket
1514 hidnplayr 148
	pop	eax
1159 hidnplayr 149
 
1519 hidnplayr 150
	jmp	.loop
1159 hidnplayr 151
 
152
  .exit:
1519 hidnplayr 153
 
1529 hidnplayr 154
}
1159 hidnplayr 155
 
156
 
1519 hidnplayr 157
;-----------------------------------------------------------------
1159 hidnplayr 158
;
159
;
1519 hidnplayr 160
;-----------------------------------------------------------------
1529 hidnplayr 161
macro	TCP_timer_640ms {
1159 hidnplayr 162
 
1529 hidnplayr 163
local	.loop
164
local	.exit
165
 
1519 hidnplayr 166
; Update TCP sequence number
167
 
1514 hidnplayr 168
	add	[TCP_sequence_num], 64000
1159 hidnplayr 169
 
1519 hidnplayr 170
; scan through all the active TCP sockets, decrementing ALL timers
171
; timers do not have the chance to wrap because of the keepalive timer will kill the socket when it expires
1159 hidnplayr 172
 
1519 hidnplayr 173
	mov	eax, net_sockets
174
  .loop:
175
	mov	eax, [eax + SOCKET.NextPtr]
176
  .check_only:
177
	or	eax, eax
178
	jz	.exit
1159 hidnplayr 179
 
1542 hidnplayr 180
	cmp	[eax + SOCKET.Protocol], IP_PROTO_TCP	  ;;; We should also check if family is AF_INET
1519 hidnplayr 181
	jne	.loop
1159 hidnplayr 182
 
1529 hidnplayr 183
	inc	[eax + TCP_SOCKET.t_idle]
184
	dec	[eax + TCP_SOCKET.timer_retransmission]
1519 hidnplayr 185
	jnz	.check_more2
1254 hidnplayr 186
 
1519 hidnplayr 187
	DEBUGF	1,"socket %x: Retransmission timer expired\n", eax
1159 hidnplayr 188
 
1519 hidnplayr 189
	push	eax
190
	call	TCP_output
191
	pop	eax
1159 hidnplayr 192
 
1519 hidnplayr 193
  .check_more2:
194
	dec	[eax + TCP_SOCKET.timer_keepalive]
195
	jnz	.check_more3
1159 hidnplayr 196
 
1519 hidnplayr 197
	DEBUGF	1,"socket %x: Keepalive expired\n", eax
1159 hidnplayr 198
 
1519 hidnplayr 199
	;;; TODO: check socket state and handle accordingly
1318 hidnplayr 200
 
1519 hidnplayr 201
  .check_more3:
202
	dec	[eax + TCP_SOCKET.timer_timed_wait]
203
	jnz	.check_more5
204
 
205
	DEBUGF	1,"socket %x: 2MSL timer expired\n", eax
206
 
207
  .check_more5:
208
	dec	[eax + TCP_SOCKET.timer_persist]
209
	jnz	.loop
210
 
211
	DEBUGF	1,"socket %x: persist timer expired\n", eax
212
 
213
	jmp	.loop
214
  .exit:
1529 hidnplayr 215
}
1519 hidnplayr 216
 
217
 
1529 hidnplayr 218
 
219
 
220
macro	TCP_checksum IP1, IP2 {
221
 
222
;-------------
223
; Pseudoheader
224
 
225
	; protocol type
226
	mov	edx, IP_PROTO_TCP
227
 
228
	; source address
1530 hidnplayr 229
	add	dl, byte [IP1+1]
230
	adc	dh, byte [IP1+0]
231
	adc	dl, byte [IP1+3]
232
	adc	dh, byte [IP1+2]
1529 hidnplayr 233
 
234
	; destination address
1530 hidnplayr 235
	adc	dl, byte [IP2+1]
236
	adc	dh, byte [IP2+0]
237
	adc	dl, byte [IP2+3]
238
	adc	dh, byte [IP2+2]
1529 hidnplayr 239
 
240
	; size
241
	adc	dl, cl
242
	adc	dh, ch
243
 
244
;---------------------
245
; Real header and data
246
 
247
	push	esi
248
	call	checksum_1
249
	call	checksum_2
250
	pop	esi
251
 
252
}	; returns in dx only
253
 
254
 
1533 hidnplayr 255
macro	TCP_sendseqinit ptr {
1529 hidnplayr 256
 
1533 hidnplayr 257
	push	edi			;;;; i dont like this static use of edi
258
	mov	edi, [ptr + TCP_SOCKET.ISS]
259
	mov	[ptr + TCP_SOCKET.SND_UP], edi
260
	mov	[ptr + TCP_SOCKET.SND_MAX], edi
261
	mov	[ptr + TCP_SOCKET.SND_NXT], edi
262
	mov	[ptr + TCP_SOCKET.SND_UNA], edi
263
	pop	edi
264
 
265
}
266
 
267
macro	TCP_rcvseqinit ptr {
268
 
269
	push	edi
270
	mov	edi, [ptr + TCP_SOCKET.IRS]
271
	inc	edi
272
	mov	[ptr + TCP_SOCKET.RCV_NXT], edi
273
	mov	[ptr + TCP_SOCKET.RCV_ADV], edi
274
	pop	edi
275
 
276
}
277
 
278
 
279
 
1249 hidnplayr 280
;-----------------------------------------------------------------
281
;
1514 hidnplayr 282
; TCP_input:
1159 hidnplayr 283
;
1514 hidnplayr 284
;  IN:  [esp] = ptr to buffer
285
;       [esp+4] = buffer size
286
;       ebx = ptr to device struct
287
;       ecx = segment size
288
;       edx = ptr to TCP segment
1196 hidnplayr 289
;
1514 hidnplayr 290
;       esi = ipv4 source address
291
;       edi = ipv4 dest   address
292
;
1196 hidnplayr 293
;  OUT: /
294
;
295
;-----------------------------------------------------------------
1249 hidnplayr 296
align 4
1514 hidnplayr 297
TCP_input:
1159 hidnplayr 298
 
1529 hidnplayr 299
       DEBUGF  1,"TCP_input size=%u\n", ecx
1514 hidnplayr 300
; Offset must be greater than or equal to the size of the standard TCP header (20) and less than or equal to the TCP length.
1254 hidnplayr 301
 
1514 hidnplayr 302
	movzx	eax, [edx + TCP_segment.DataOffset]
303
	and	eax, 0xf0
1529 hidnplayr 304
	shr	al, 2
1514 hidnplayr 305
 
1529 hidnplayr 306
	DEBUGF	1,"headersize=%u\n", eax
1514 hidnplayr 307
 
308
	cmp	eax, 20
309
	jl	.drop
310
 
311
;-------------------------------
312
; Now, re-calculate the checksum
313
 
1529 hidnplayr 314
	push	eax ecx edx
315
	pushw	[edx + TCP_segment.Checksum]
316
	mov	[edx + TCP_segment.Checksum], 0
317
	push	esi edi
1514 hidnplayr 318
	mov	esi, edx
1530 hidnplayr 319
	TCP_checksum (esp), (esp+4)
1529 hidnplayr 320
	pop	esi edi ; yes, swap them (we dont need dest addr)
321
	pop	cx	; previous checksum
322
	cmp	cx, dx
323
	pop	edx ecx esi
1514 hidnplayr 324
	jnz	.drop
325
 
326
	DEBUGF	1,"Checksum is correct\n"
327
 
1529 hidnplayr 328
	sub	ecx, esi	; update packet size
329
	jl	.drop
1534 hidnplayr 330
	DEBUGF	1,"we got %u bytes of data\n", ecx
1529 hidnplayr 331
 
1514 hidnplayr 332
;-----------------------------------------------------------------------------------------
333
; Check if this packet has a timestamp option (We do it here so we can process it quickly)
334
 
1529 hidnplayr 335
	cmp	esi, 20 + 12					; Timestamp option is 12 bytes
1514 hidnplayr 336
	jl	.no_timestamp
337
	je	.is_ok
338
 
1529 hidnplayr 339
	cmp	byte [edx + TCP_segment.Data + 12], TCP_OPT_EOL ; end of option list
1514 hidnplayr 340
	jne	.no_timestamp
341
 
342
  .is_ok:
343
	test	[edx + TCP_segment.Flags], TH_SYN		; SYN flag must not be set
344
	jnz	.no_timestamp
345
 
346
	cmp	dword [edx + TCP_segment.Data], 0x0101080a	; Timestamp header
347
	jne	.no_timestamp
348
 
349
	DEBUGF	1,"timestamp ok\n"
350
 
1529 hidnplayr 351
	; TODO: Parse the option
1514 hidnplayr 352
	; TODO: Set a Bit in the TCP to tell all options are parsed
353
 
354
  .no_timestamp:
355
 
356
;-------------------------------------------
357
; Convert Big-endian values to little endian
358
 
1543 hidnplayr 359
	ntohd	[edx + TCP_segment.SequenceNumber]
360
	ntohd	[edx + TCP_segment.AckNumber]
1514 hidnplayr 361
 
1543 hidnplayr 362
	ntohw	[edx + TCP_segment.Window]
363
	ntohw	[edx + TCP_segment.UrgentPointer]
364
	ntohw	[edx + TCP_segment.SourcePort]
365
	ntohw	[edx + TCP_segment.DestinationPort]
1514 hidnplayr 366
 
367
;------------------------------------------------------------
368
; Next thing to do is find the TCB (thus, the socket pointer)
369
 
1274 hidnplayr 370
; IP Packet TCP Destination Port = local Port
1514 hidnplayr 371
; (IP Packet SenderAddress = Remote IP)  OR  (Remote IP = 0)
1318 hidnplayr 372
; (IP Packet TCP Source Port = remote Port)  OR (remote Port = 0)
1159 hidnplayr 373
 
374
	mov	ebx, net_sockets
375
 
1249 hidnplayr 376
  .socket_loop:
1514 hidnplayr 377
	mov	ebx, [ebx + SOCKET.NextPtr]
1159 hidnplayr 378
	or	ebx, ebx
1514 hidnplayr 379
	jz	.drop_with_reset
1159 hidnplayr 380
 
1543 hidnplayr 381
	cmp	[ebx + SOCKET.Domain], AF_INET4
1249 hidnplayr 382
	jne	.socket_loop
1159 hidnplayr 383
 
1543 hidnplayr 384
	cmp	[ebx + SOCKET.Protocol], IP_PROTO_TCP
385
	jne	.socket_loop
386
 
1514 hidnplayr 387
	mov	ax, [edx + TCP_segment.DestinationPort]
388
	cmp	[ebx + TCP_SOCKET.LocalPort], ax
389
	jne	.socket_loop
390
 
391
	mov	eax, [ebx + IP_SOCKET.RemoteIP]
1543 hidnplayr 392
	cmp	eax, edi			; edi is source ip from packet
1249 hidnplayr 393
	je	@f
394
	test	eax, eax
1514 hidnplayr 395
	jnz	.socket_loop
1249 hidnplayr 396
       @@:
1159 hidnplayr 397
 
1514 hidnplayr 398
	mov	ax, [ebx + TCP_SOCKET.RemotePort]
399
	cmp	[edx + TCP_segment.SourcePort] , ax
1274 hidnplayr 400
	je	.found_socket
1249 hidnplayr 401
	test	ax, ax
1254 hidnplayr 402
	jnz	.socket_loop
1274 hidnplayr 403
  .found_socket:
1529 hidnplayr 404
	DEBUGF	1,"Socket ptr: %x\n", ebx
1254 hidnplayr 405
 
1514 hidnplayr 406
; ebx now contains the pointer to the socket
1257 hidnplayr 407
 
1514 hidnplayr 408
;----------------------------
409
; Check if socket isnt closed
410
 
1529 hidnplayr 411
	cmp	[ebx + TCP_SOCKET.t_state], TCB_CLOSED
1514 hidnplayr 412
	je	.drop
413
 
414
;----------------
415
; Lock the socket
416
 
1529 hidnplayr 417
;;        add     ebx, SOCKET.lock ; TODO: figure out if we should lock now already
418
;;        call    wait_mutex
419
;;        sub     ebx, SOCKET.lock
1159 hidnplayr 420
 
1529 hidnplayr 421
	DEBUGF	1,"Socket locked\n"
1159 hidnplayr 422
 
1543 hidnplayr 423
;---------------------------------------
424
; unscale the window into a 32 bit value
1529 hidnplayr 425
 
1514 hidnplayr 426
	movzx	eax, [edx + TCP_segment.Window]
1534 hidnplayr 427
	push	ecx
1529 hidnplayr 428
	mov	cl, [ebx + TCP_SOCKET.SND_SCALE]
1514 hidnplayr 429
	shl	eax, cl
1543 hidnplayr 430
	mov	dword [edx + TCP_segment.Window], eax	; word after window is checksum, we dont need checksum anymore
1534 hidnplayr 431
	pop	ecx
1514 hidnplayr 432
 
433
;-----------------------------------
434
; Is this socket a listening socket?
435
 
1533 hidnplayr 436
	test	[ebx + SOCKET.options], SO_ACCEPTCON
1543 hidnplayr 437
	jz	.no_listening_socket
1514 hidnplayr 438
 
1543 hidnplayr 439
	call	SOCKET_fork
440
	jz	.drop
441
 
442
	push	[edx + TCP_segment.DestinationPort]
443
	pop	[eax + TCP_SOCKET.LocalPort]
444
 
445
	push	[edx - IPv4_Packet.DataOrOptional + IPv4_Packet.DestinationAddress]	;;; FIXME
446
	pop	[eax + IP_SOCKET.LocalIP]
447
 
448
	push	[edx - IPv4_Packet.DataOrOptional + IPv4_Packet.SourceAddress]	   ;;; FIXME
449
	pop	[eax + IP_SOCKET.RemoteIP]
450
 
451
	mov	[eax + TCP_SOCKET.t_state], TCB_LISTEN
452
 
453
	jmp	.not_uni_xfer
454
 
455
  .no_listening_socket:
456
 
1529 hidnplayr 457
;-------------------------------------
458
; Reset idle timer and keepalive timer
1514 hidnplayr 459
 
1529 hidnplayr 460
	mov	[ebx + TCP_SOCKET.t_idle], 0
461
	mov	[ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
1514 hidnplayr 462
 
1529 hidnplayr 463
;--------------------
464
; Process TCP options
1514 hidnplayr 465
 
1529 hidnplayr 466
	cmp	esi, 20 			; esi is headersize
467
	je	.no_options
1514 hidnplayr 468
 
1529 hidnplayr 469
	DEBUGF	1,"Segment has options\n"
1514 hidnplayr 470
 
1530 hidnplayr 471
	cmp	[ebx + TCP_SOCKET.t_state], TCB_LISTEN		; no options when in listen state
1543 hidnplayr 472
	jz	.not_uni_xfer					; also no header prediction
1514 hidnplayr 473
 
1529 hidnplayr 474
	lea	edi, [edx + TCP_segment.Data]
475
	lea	eax, [edx + esi]
1514 hidnplayr 476
 
1529 hidnplayr 477
  .opt_loop:
478
	cmp	edi, eax
479
	jge	.no_options
1514 hidnplayr 480
 
1529 hidnplayr 481
	cmp	byte [edi], TCP_OPT_EOL 	; end of option list?
482
	jz	.no_options
1514 hidnplayr 483
 
1529 hidnplayr 484
	cmp	byte [edi], TCP_OPT_NOP 	; nop ?
485
	jz	.opt_nop
1514 hidnplayr 486
 
1529 hidnplayr 487
	cmp	byte [edi], TCP_OPT_MAXSEG
488
	je	.opt_maxseg
1514 hidnplayr 489
 
1529 hidnplayr 490
	cmp	byte [edi], TCP_OPT_WINDOW
491
	je	.opt_window
1514 hidnplayr 492
 
1529 hidnplayr 493
	cmp	byte [edi], TCP_OPT_TIMESTAMP
494
	je	.opt_timestamp
1514 hidnplayr 495
 
1529 hidnplayr 496
	jmp	.no_options	; If we reach here, some unknown options were received, skip them all!
1514 hidnplayr 497
 
1529 hidnplayr 498
  .opt_nop:
499
	inc	edi
500
	jmp	.opt_loop
1514 hidnplayr 501
 
1529 hidnplayr 502
  .opt_maxseg:
503
	cmp	byte [edi+1], 4
504
	jne	.no_options		; error occured, ignore all options!
1514 hidnplayr 505
 
1529 hidnplayr 506
	test	[edx + TCP_segment.Flags], TH_SYN
507
	jz	@f
508
 
1530 hidnplayr 509
	movzx	eax, word[edi+2]
510
	rol	ax, 8
1533 hidnplayr 511
	DEBUGF	1,"Maxseg: %u\n", ax
1529 hidnplayr 512
 
1530 hidnplayr 513
	mov	[ebx + TCP_SOCKET.t_maxseg], eax
514
 
1529 hidnplayr 515
       @@:
516
	add	edi, 4
517
	jmp	.opt_loop
518
 
519
 
520
  .opt_window:
521
	cmp	byte [edi+1], 3
522
	jne	.no_options
523
 
524
	test	[edx + TCP_segment.Flags], TH_SYN
525
	jz	@f
526
 
1533 hidnplayr 527
	DEBUGF	1,"Got window option\n"
1529 hidnplayr 528
 
529
	;;;;;
530
       @@:
531
	add	edi, 3
532
	jmp	.opt_loop
533
 
534
 
535
  .opt_timestamp:
536
	cmp	byte [edi+1], 10
537
	jne	.no_options
538
 
1533 hidnplayr 539
	DEBUGF	1,"Got timestamp option\n"
1529 hidnplayr 540
 
541
	;;;;;
542
 
543
	add	edi, 10
544
	jmp	.opt_loop
545
 
546
  .no_options:
547
 
1514 hidnplayr 548
;-----------------------------------------------------------------------
549
; Time to do some header prediction (Original Principle by Van Jacobson)
550
 
551
; There are two common cases for an uni-directional data transfer.
552
;
553
; General rule: the packets has no control flags, is in-sequence,
554
;   window width didnt change and we're not retransmitting.
555
;
556
; Second rules:
557
;  -  If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
558
;      In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
559
;
560
;  -  If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
561
;      If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
562
 
1529 hidnplayr 563
	cmp	[ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
1514 hidnplayr 564
	jnz	.not_uni_xfer
565
 
1529 hidnplayr 566
	test	[edx + TCP_segment.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
1514 hidnplayr 567
	jnz	.not_uni_xfer
568
 
1529 hidnplayr 569
	test	[edx + TCP_segment.Flags], TH_ACK
1514 hidnplayr 570
	jz	.not_uni_xfer
571
 
572
	mov	eax, [edx + TCP_segment.SequenceNumber]
573
	cmp	eax, [ebx + TCP_SOCKET.RCV_NXT]
574
	jne	.not_uni_xfer
1719 hidnplayr 575
	DEBUGF	1,"TCP_segment.window=%u\n", [edx + TCP_segment.Window]:4
576
	DEBUGF	1,"TCP_SOCKET.SND_WND=%u\n", [ebx + TCP_SOCKET.SND_WND]:4
1543 hidnplayr 577
	mov	eax, dword [edx + TCP_segment.Window]
1536 hidnplayr 578
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
579
	jne	.not_uni_xfer
1514 hidnplayr 580
 
581
	mov	eax, [ebx + TCP_SOCKET.SND_NXT]
582
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
583
	jne	.not_uni_xfer
584
 
585
;---------------------------------------
586
; check if we are sender in the uni-xfer
587
 
588
; If the following 4 conditions are all true, this segment is a pure ACK.
589
;
1529 hidnplayr 590
; - The segment contains no data.
591
	test	ecx, ecx
1514 hidnplayr 592
	jnz	.not_sender
1274 hidnplayr 593
 
1529 hidnplayr 594
; - The congestion window is greater than or equal to the current send window.
1514 hidnplayr 595
;     This test is true only if the window is fully open, that is, the connection is not in the middle of slow start or congestion avoidance.
596
	mov	eax, [ebx + TCP_SOCKET.SND_CWND]
597
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
598
	jl	.not_uni_xfer
1318 hidnplayr 599
 
1529 hidnplayr 600
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
1534 hidnplayr 601
	mov	eax, [edx + TCP_segment.AckNumber]
602
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
1529 hidnplayr 603
	jg	.not_uni_xfer
604
 
605
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
1534 hidnplayr 606
	sub	eax, [ebx + TCP_SOCKET.SND_UNA]
1529 hidnplayr 607
	jle	.not_uni_xfer
608
 
1514 hidnplayr 609
	DEBUGF	1,"Header prediction: we are sender\n"
1274 hidnplayr 610
 
1514 hidnplayr 611
;---------------------------------
612
; Packet is a pure ACK, process it
1274 hidnplayr 613
 
1514 hidnplayr 614
; Update RTT estimators
1159 hidnplayr 615
 
1514 hidnplayr 616
; Delete acknowledged bytes from send buffer
1719 hidnplayr 617
	pusha
1536 hidnplayr 618
	mov	ecx, eax
1533 hidnplayr 619
	lea	eax, [ebx + STREAM_SOCKET.snd]
1529 hidnplayr 620
	call	SOCKET_ring_free
1719 hidnplayr 621
	popa
1529 hidnplayr 622
 
1536 hidnplayr 623
; update window pointers
624
	mov	eax, [edx + TCP_segment.AckNumber]
625
	dec	eax
626
	mov	[ebx + TCP_SOCKET.SND_WL1], eax
627
 
1514 hidnplayr 628
; Stop retransmit timer
1519 hidnplayr 629
	mov	[ebx + TCP_SOCKET.timer_ack], 0
1159 hidnplayr 630
 
1514 hidnplayr 631
; Awaken waiting processes
1519 hidnplayr 632
	mov	eax, ebx
633
	call	SOCKET_notify_owner
1318 hidnplayr 634
 
1719 hidnplayr 635
;; Generate more output                  FIXME
1536 hidnplayr 636
;;        mov     eax, ebx
637
;;        call    TCP_output
638
;;
639
;;        jmp     .drop
1719 hidnplayr 640
	jmp	.ack_processed
1254 hidnplayr 641
 
1514 hidnplayr 642
;-------------------------------------------------
643
; maybe we are the receiver in the uni-xfer then..
644
 
645
  .not_sender:
1529 hidnplayr 646
; - The amount of data in the segment is greater than 0 (data count is in ecx)
1514 hidnplayr 647
 
1529 hidnplayr 648
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
1514 hidnplayr 649
	mov	eax, [edx + TCP_segment.AckNumber]
650
	cmp	eax, [ebx + TCP_SOCKET.SND_UNA]
651
	jne	.not_uni_xfer
652
 
1719 hidnplayr 653
; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp).
1514 hidnplayr 654
 
1719 hidnplayr 655
;;;;;;;     TODO
656
 
1514 hidnplayr 657
	jnz	.not_uni_xfer
658
 
659
;-------------------------------------
660
; Complete processing of received data
661
 
662
	DEBUGF	1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx
663
 
1719 hidnplayr 664
	pusha
1529 hidnplayr 665
	add	esi, edx
1533 hidnplayr 666
	lea	eax, [ebx + STREAM_SOCKET.rcv]
667
	call	SOCKET_ring_write			; Add the data to the socket buffer
1514 hidnplayr 668
 
1533 hidnplayr 669
	mov	eax, ebx
670
	call	SOCKET_notify_owner
1719 hidnplayr 671
	popa
1533 hidnplayr 672
 
1529 hidnplayr 673
	add	[ebx + TCP_SOCKET.RCV_NXT], ecx 	; Update sequence number with number of bytes we have copied
674
	or	[ebx + TCP_SOCKET.t_flags], TF_DELACK	; Set delayed ack flag
1514 hidnplayr 675
 
676
	jmp	.drop
677
 
678
;----------------------------------------------------
1529 hidnplayr 679
; Header prediction failed, doing it the slow way..     ;;;;; current implementation of header prediction destroys some regs (ecx) !!
1514 hidnplayr 680
 
681
  .not_uni_xfer:
682
 
1533 hidnplayr 683
	DEBUGF	1,"Header prediction failed\n"		; time to do it the "slow" way :)
1514 hidnplayr 684
 
685
;------------------------------
686
; Calculate receive window size
687
 
688
	;;;;
689
 
1529 hidnplayr 690
	cmp	[ebx + TCP_SOCKET.t_state], TCB_LISTEN
1514 hidnplayr 691
	je	.LISTEN
692
 
1529 hidnplayr 693
	cmp	[ebx + TCP_SOCKET.t_state], TCB_SYN_SENT
1514 hidnplayr 694
	je	.SYN_SENT
695
 
696
;--------------------------------------------
697
; Protection Against Wrapped Sequence Numbers
698
 
1533 hidnplayr 699
; First, check if timestamp is present
1514 hidnplayr 700
 
701
;;;; TODO
702
 
703
; Then, check if at least some bytes of data are within window
704
 
705
;;;; TODO
706
 
707
	jmp	.trim_then_step6
708
 
1529 hidnplayr 709
;-------------
710
; Passive Open
711
 
1249 hidnplayr 712
align 4
1514 hidnplayr 713
.LISTEN:
1196 hidnplayr 714
 
1514 hidnplayr 715
	DEBUGF	1,"TCP state: listen\n"
1159 hidnplayr 716
 
1543 hidnplayr 717
	test	[edx + TCP_segment.Flags], TH_RST	;;; TODO: kill new socket on error
1514 hidnplayr 718
	jnz	.drop
1159 hidnplayr 719
 
1514 hidnplayr 720
	test	[edx + TCP_segment.Flags], TH_ACK
721
	jnz	.drop_with_reset
1159 hidnplayr 722
 
1514 hidnplayr 723
	test	[edx + TCP_segment.Flags], TH_SYN
724
	jz	.drop
1159 hidnplayr 725
 
1533 hidnplayr 726
 
1514 hidnplayr 727
	; TODO: check if it's a broadcast or multicast, and drop if so
1159 hidnplayr 728
 
1529 hidnplayr 729
;-----------------------
730
; Fill in some variables
1514 hidnplayr 731
 
1529 hidnplayr 732
	add	[TCP_sequence_num], 64000
1514 hidnplayr 733
 
1529 hidnplayr 734
	push	[edx + TCP_segment.SourcePort]
735
	pop	[eax + TCP_SOCKET.RemotePort]
1514 hidnplayr 736
 
1529 hidnplayr 737
	push	[edx + TCP_segment.SequenceNumber]
738
	pop	[eax + TCP_SOCKET.IRS]
1159 hidnplayr 739
 
1529 hidnplayr 740
	push	[eax + TCP_SOCKET.ISS]
741
	pop	[eax + TCP_SOCKET.SND_NXT]
1159 hidnplayr 742
 
1543 hidnplayr 743
	TCP_sendseqinit eax
744
	TCP_rcvseqinit eax
745
 
1529 hidnplayr 746
	mov	[eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
747
	mov	[eax + TCP_SOCKET.t_flags], TF_ACKNOW
1543 hidnplayr 748
	mov	[eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval  ;;;; macro
1159 hidnplayr 749
 
1543 hidnplayr 750
	add	eax, STREAM_SOCKET.snd
751
	call	SOCKET_ring_create
752
 
753
	add	eax, STREAM_SOCKET.rcv - STREAM_SOCKET.snd
754
	call	SOCKET_ring_create
755
 
756
	sub	eax, STREAM_SOCKET.rcv
757
 
758
	mov	[eax + SOCKET.lock], 0
759
	mov	ebx, eax	; if there is data, it must arrive in this new socket!
1514 hidnplayr 760
	jmp	.trim_then_step6
1159 hidnplayr 761
 
1254 hidnplayr 762
 
1529 hidnplayr 763
;------------
764
; Active Open
1159 hidnplayr 765
 
1514 hidnplayr 766
align 4
767
.SYN_SENT:
1281 hidnplayr 768
 
1514 hidnplayr 769
	DEBUGF	1,"TCP state: syn_sent\n"
1159 hidnplayr 770
 
1514 hidnplayr 771
	test	[edx + TCP_segment.Flags], TH_ACK
772
	jz	@f
1281 hidnplayr 773
 
1514 hidnplayr 774
	mov	eax, [edx + TCP_segment.AckNumber]
775
	cmp	eax, [ebx + TCP_SOCKET.ISS]
776
	jle	.drop_with_reset
1533 hidnplayr 777
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
778
	jg	.drop_with_reset
1514 hidnplayr 779
       @@:
1281 hidnplayr 780
 
1514 hidnplayr 781
	test	[edx + TCP_segment.Flags], TH_RST
782
	jz	@f
1281 hidnplayr 783
 
1514 hidnplayr 784
	test	[edx + TCP_segment.Flags], TH_ACK
785
	jz	.drop
1281 hidnplayr 786
 
1719 hidnplayr 787
	mov	eax, ebx
1716 hidnplayr 788
	mov	ebx, ECONNREFUSED
789
	call	TCP_drop
1159 hidnplayr 790
 
1514 hidnplayr 791
	jmp	.drop
792
       @@:
1159 hidnplayr 793
 
1514 hidnplayr 794
	test	[edx + TCP_segment.Flags], TH_SYN
795
	jz	.drop
1318 hidnplayr 796
 
1529 hidnplayr 797
; at this point, segment seems to be valid
798
 
1514 hidnplayr 799
	test	[edx + TCP_segment.Flags], TH_ACK
1529 hidnplayr 800
	jz	.no_syn_ack
1514 hidnplayr 801
 
1529 hidnplayr 802
; now, process received SYN in response to an active open
803
 
1514 hidnplayr 804
	mov	eax, [edx + TCP_segment.AckNumber]
805
	mov	[ebx + TCP_SOCKET.SND_UNA], eax
806
	cmp	eax, [ebx + TCP_SOCKET.SND_NXT]
807
	jle	@f
808
	mov	[ebx + TCP_SOCKET.SND_NXT], eax
1529 hidnplayr 809
       @@:
1514 hidnplayr 810
 
1529 hidnplayr 811
  .no_syn_ack:
1514 hidnplayr 812
 
1529 hidnplayr 813
	mov	[ebx + TCP_SOCKET.timer_retransmission], 0	; disable retransmission
1514 hidnplayr 814
 
1529 hidnplayr 815
	push	[edx + TCP_segment.SequenceNumber]
816
	pop	[ebx + TCP_SOCKET.IRS]
817
 
1533 hidnplayr 818
	TCP_rcvseqinit ebx
1529 hidnplayr 819
 
820
	mov	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
821
 
822
	mov	eax, [ebx + TCP_SOCKET.SND_UNA]
823
	cmp	eax, [ebx + TCP_SOCKET.ISS]
824
	jle	.simultaneous_open
825
 
826
	test	[edx + TCP_segment.Flags], TH_ACK
827
	jz	.simultaneous_open
828
 
829
	DEBUGF	1,"TCP: active open\n"
830
 
831
; TODO: update stats
1533 hidnplayr 832
; TODO: set general socket state to connected
1514 hidnplayr 833
 
834
	mov	[ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
835
 
836
; TODO: check if we should scale the connection (567-572)
837
; TODO: update RTT estimators
838
 
1529 hidnplayr 839
	jmp	.trimthenstep6
1514 hidnplayr 840
 
1529 hidnplayr 841
  .simultaneous_open:
1514 hidnplayr 842
 
1529 hidnplayr 843
	DEBUGF	1,"TCP: simultaneous open\n"
1514 hidnplayr 844
; We have received a syn but no ACK, so we are having a simultaneous open..
845
	mov	[ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
846
 
847
;-------------------------------------
848
; Common processing for receipt of SYN
849
 
850
  .trimthenstep6:
851
 
852
	inc	[edx + TCP_segment.SequenceNumber]
853
 
854
	cmp	cx, [ebx + TCP_SOCKET.RCV_WND]
855
	jle	@f
856
 
857
	movzx	eax, cx
858
	sub	ax, [ebx + TCP_SOCKET.RCV_WND]
859
	; TODO: 592
860
	mov	cx, [ebx + TCP_SOCKET.RCV_WND]
861
	; TODO...
862
       @@:
863
	;;;;;
1719 hidnplayr 864
	jmp	.ack_processed
1514 hidnplayr 865
 
866
 
1529 hidnplayr 867
  .trim_then_step6:
1159 hidnplayr 868
 
1514 hidnplayr 869
;----------------------------
870
; trim any data not in window
1159 hidnplayr 871
 
1533 hidnplayr 872
	DEBUGF	1,"Trimming window\n"
873
 
1514 hidnplayr 874
	mov	eax, [ebx + TCP_SOCKET.RCV_NXT]
875
	sub	eax, [edx + TCP_segment.SequenceNumber]
1533 hidnplayr 876
	jz	.no_duplicate
1274 hidnplayr 877
 
1514 hidnplayr 878
	test	[edx + TCP_segment.Flags], TH_SYN
879
	jz	.no_drop
880
 
881
	and	[edx + TCP_segment.Flags], not (TH_SYN)
882
	inc	[edx + TCP_segment.SequenceNumber]
883
 
884
	cmp	[edx + TCP_segment.UrgentPointer], 1
885
	jl	@f
886
 
887
	dec	[edx + TCP_segment.UrgentPointer]
888
 
889
	jmp	.no_drop
890
       @@:
891
 
892
	and	[edx + TCP_segment.Flags], not (TH_URG)
893
	dec	eax
1533 hidnplayr 894
	jz	.no_duplicate
1514 hidnplayr 895
  .no_drop:
896
 
1533 hidnplayr 897
	DEBUGF	1,"Going to drop %u out of %u bytes\n", eax, ecx
1529 hidnplayr 898
 
1514 hidnplayr 899
; eax holds number of bytes to drop
900
 
901
;----------------------------------
902
; Check for entire duplicate packet
903
 
904
	cmp	eax, ecx
905
	jge	.duplicate
906
 
907
	;;; TODO: figure 28.30
908
 
909
;------------------------
910
; Check for duplicate FIN
911
 
912
	test	[edx + TCP_segment.Flags], TH_FIN
913
	jz	@f
914
	inc	ecx
915
	cmp	eax, ecx
916
	dec	ecx
917
	jne	@f
918
 
919
	mov	eax, ecx
920
	and	[edx + TCP_segment.Flags], not TH_FIN
1529 hidnplayr 921
	or	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1514 hidnplayr 922
	jmp	.no_duplicate
923
       @@:
924
 
925
	; Handle the case when a bound socket connects to itself
926
	; Allow packets with a SYN and an ACKto continue with the processing
927
 
928
;-------------------------------------
929
; Generate duplicate ACK if nescessary
930
 
931
; This code also handles simultaneous half-open or self-connects
932
 
933
	test	eax, eax
934
	jnz	.drop_after_ack
935
 
936
	cmp	[edx + TCP_segment.Flags], TH_ACK
937
	jz	.drop_after_ack
938
 
939
  .duplicate:
940
 
1533 hidnplayr 941
	DEBUGF	1,"Duplicate received\n"
1529 hidnplayr 942
 
1514 hidnplayr 943
;----------------------------------------
944
; Update statistics for duplicate packets
945
 
946
	;;; TODO
947
 
1529 hidnplayr 948
	jmp	.drop	       ;;; DROP the packet ??
1514 hidnplayr 949
 
950
  .no_duplicate:
951
 
952
;-----------------------------------------------
953
; Remove duplicate data and update urgent offset
954
 
955
	add	[edx + TCP_segment.SequenceNumber], eax
956
 
957
	;;; TODO
958
 
959
	sub	[edx + TCP_segment.UrgentPointer], ax
960
	jg	@f
961
 
962
	and	[edx + TCP_segment.Flags], not (TH_URG)
963
	mov	[edx + TCP_segment.UrgentPointer], 0
964
       @@:
965
 
966
;--------------------------------------------------
967
; Handle data that arrives after process terminates
968
 
969
	cmp	[ebx + SOCKET.PID], 0
1533 hidnplayr 970
	jg	@f
1514 hidnplayr 971
 
972
	cmp	[ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT
973
	jle	@f
974
 
975
	test	ecx, ecx
976
	jz	@f
977
 
978
	;;; Close the socket
979
	;;; update stats
980
 
981
	jmp	.drop_with_reset
982
       @@:
983
 
984
;----------------------------------------
985
; Remove data beyond right edge of window
986
 
987
	mov	eax, [edx + TCP_segment.SequenceNumber]
988
	add	eax, ecx
989
	sub	eax, [ebx + TCP_SOCKET.RCV_NXT]
990
	sub	ax, [ebx + TCP_SOCKET.RCV_WND]
991
 
992
	; eax now holds the number of bytes to drop
993
 
994
	jle	.no_excess_data
995
 
996
	;;; TODO: update stats
997
 
998
	cmp	eax, ecx
999
	jl	.dont_drop_all
1000
 
1001
;;; TODO 700-736
1002
 
1003
  .dont_drop_all:
1004
 
1005
  .no_excess_data:
1006
 
1007
;-----------------
1008
; Record timestamp
1009
 
1010
	;;; TODO 737-746
1011
 
1012
;------------------
1013
; Process RST flags
1014
 
1015
	test	[edx + TCP_segment.Flags], TH_RST
1016
	jz	.rst_skip
1017
 
1529 hidnplayr 1018
	DEBUGF	1,"Got an RST flag"
1019
 
1514 hidnplayr 1020
	mov	eax, [ebx + TCP_SOCKET.t_state]
1021
	shl	eax, 2
1022
	jmp	dword [eax + .rst_sw_list]
1023
 
1024
  .rst_sw_list:
1025
	dd	.rst_skip	;TCB_CLOSED
1026
	dd	.rst_skip	;TCB_LISTEN
1027
	dd	.rst_skip	;TCB_SYN_SENT
1028
	dd	.econnrefused	;TCB_SYN_RECEIVED
1029
	dd	.econnreset	;TCB_ESTABLISHED
1030
	dd	.econnreset	;TCB_CLOSE_WAIT
1031
	dd	.econnreset	;TCB_FIN_WAIT_1
1032
	dd	.rst_close	;TCB_CLOSING
1033
	dd	.rst_close	;TCB_LAST_ACK
1034
	dd	.econnreset	;TCB_FIN_WAIT_2
1035
	dd	.rst_close	;TCB_TIMED_WAIT
1036
 
1037
  .econnrefused:
1038
 
1529 hidnplayr 1039
	DEBUGF	1,"Connection refused"
1040
 
1514 hidnplayr 1041
	;;; TODO: debug info
1042
 
1043
	jmp	.close
1044
 
1045
  .econnreset:
1046
 
1529 hidnplayr 1047
	DEBUGF	1,"Connection reset"
1048
 
1514 hidnplayr 1049
	;;; TODO: debug info
1529 hidnplayr 1050
  .close:
1514 hidnplayr 1051
 
1529 hidnplayr 1052
	DEBUGF	1,"Closing connection"
1053
 
1514 hidnplayr 1054
	;;; update stats
1055
 
1056
  .rst_close:
1057
 
1534 hidnplayr 1058
	DEBUGF	1,"Closing with reset\n"
1529 hidnplayr 1059
 
1514 hidnplayr 1060
	;;; Close the socket
1061
	jmp	.drop
1062
 
1063
  .rst_skip:
1064
 
1065
;--------------------------------------
1066
; handle SYN-full and ACK-less segments
1067
 
1068
	test	[edx + TCP_segment.Flags], TH_SYN
1069
	jz	@f
1070
 
1719 hidnplayr 1071
	mov	eax, ebx
1716 hidnplayr 1072
	mov	ebx, ECONNRESET
1073
	call	TCP_drop
1074
 
1514 hidnplayr 1075
	jmp	.drop_with_reset
1076
 
1077
	test	[edx + TCP_segment.Flags], TH_ACK
1078
	jz	.drop
1534 hidnplayr 1079
      @@:
1514 hidnplayr 1080
 
1719 hidnplayr 1081
;---------------
1082
; ACK processing
1083
 
1514 hidnplayr 1084
	cmp	[ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
1719 hidnplayr 1085
	jnz	.no_syn_rcv
1514 hidnplayr 1086
 
1534 hidnplayr 1087
	DEBUGF	1,"TCP state = syn received\n"
1533 hidnplayr 1088
 
1719 hidnplayr 1089
	;;;;;  801-815
1514 hidnplayr 1090
 
1719 hidnplayr 1091
  .no_syn_rcv:
1514 hidnplayr 1092
 
1719 hidnplayr 1093
; check for duplicate ACK
1533 hidnplayr 1094
 
1719 hidnplayr 1095
	mov	eax, [edx + TCP_segment.AckNumber]
1096
	cmp	eax, [ebx + TCP_SOCKET.SND_UNA]
1097
	jg	.not_dup_ack
1514 hidnplayr 1098
 
1719 hidnplayr 1099
	DEBUGF	1,"Duplicate ACK\n"
1514 hidnplayr 1100
 
1719 hidnplayr 1101
	test	ecx, ecx
1102
	jnz	.ack_processed
1514 hidnplayr 1103
 
1719 hidnplayr 1104
	mov	eax, dword [edx + TCP_segment.Window]
1105
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
1106
	jne	.ack_processed
1533 hidnplayr 1107
 
1719 hidnplayr 1108
; Process the duplicate ACK
1109
 
1110
	;;;;; 833 - 878
1111
 
1112
;;;        call    TCP_output
1113
	jmp	.drop
1114
 
1115
  .not_dup_ack:
1116
 
1117
	DEBUGF	1,"new ACK\n"
1118
 
1119
 
1514 hidnplayr 1120
;-------------------------------------------------
1519 hidnplayr 1121
; If the congestion window was inflated to account
1719 hidnplayr 1122
; for the other side's cached packets, retract it
1514 hidnplayr 1123
 
1124
	;;;; 888 -  902
1125
 
1126
 
1127
;------------------------------------------
1128
; RTT measurements and retransmission timer
1129
 
1130
	;;;;; 903 - 926
1131
 
1519 hidnplayr 1132
	mov	[ebx + TCP_SOCKET.timer_retransmission], 0
1514 hidnplayr 1133
 
1519 hidnplayr 1134
	mov	eax, [ebx + TCP_SOCKET.SND_MAX]
1135
	cmp	eax, [edx + TCP_segment.AckNumber]
1136
	je	.all_outstanding
1543 hidnplayr 1137
	mov	[ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value (use a macro for it)
1519 hidnplayr 1138
  .all_outstanding:
1139
 
1514 hidnplayr 1140
;-------------------------------------------
1141
; Open congestion window in response to ACKs
1142
 
1143
	;;;;
1144
 
1145
 
1146
;------------------------------------------
1147
; Remove acknowledged data from send buffer
1148
 
1536 hidnplayr 1149
	pusha
1150
	mov	ecx, [edx + TCP_segment.AckNumber]
1719 hidnplayr 1151
	sub	ecx, [ebx + TCP_SOCKET.SND_UNA] 	; ecx now holds number of bytes acked
1152
 
1533 hidnplayr 1153
	lea	eax, [ebx + STREAM_SOCKET.snd]
1536 hidnplayr 1154
	call	SOCKET_ring_free
1155
	popa
1514 hidnplayr 1156
 
1719 hidnplayr 1157
;---------------------------------------
1158
; Wake up process waiting on send buffer
1536 hidnplayr 1159
 
1719 hidnplayr 1160
	mov	eax, ebx
1161
	call	SOCKET_notify_owner
1536 hidnplayr 1162
 
1719 hidnplayr 1163
; Update TCB
1542 hidnplayr 1164
 
1536 hidnplayr 1165
	mov	eax, [edx + TCP_segment.AckNumber]
1166
	mov	[ebx + TCP_SOCKET.SND_UNA], eax
1167
 
1168
	cmp	eax, [ebx + TCP_SOCKET.SND_NXT]
1169
	jl	@f
1170
	mov	[ebx + TCP_SOCKET.SND_NXT], eax
1171
       @@:
1172
 
1719 hidnplayr 1173
; General ACK handling complete
1174
; Now do the state-specific ones
1536 hidnplayr 1175
 
1514 hidnplayr 1176
	mov	eax, [ebx + TCP_SOCKET.t_state]
1719 hidnplayr 1177
	jmp	dword [eax*4 + .ACK_sw_list]
1514 hidnplayr 1178
 
1179
  .ACK_sw_list:
1719 hidnplayr 1180
	dd	.ack_processed	;TCB_CLOSED
1181
	dd	.ack_processed	;TCB_LISTEN
1182
	dd	.ack_processed	;TCB_SYN_SENT
1183
	dd	.ack_processed	;TCB_SYN_RECEIVED
1184
	dd	.ack_processed	;TCB_ESTABLISHED
1185
	dd	.ack_processed	;TCB_CLOSE_WAIT
1186
	dd	.ack_fw1	;TCB_FIN_WAIT_1
1187
	dd	.ack_c		;TCB_CLOSING
1188
	dd	.ack_la 	;TCB_LAST_ACK
1189
	dd	.ack_processed	;TCB_FIN_WAIT_2
1190
	dd	.ack_tw 	;TCB_TIMED_WAIT
1514 hidnplayr 1191
 
1192
 
1719 hidnplayr 1193
  .ack_fw1:
1514 hidnplayr 1194
 
1719 hidnplayr 1195
;;; TODO: 963
1514 hidnplayr 1196
 
1719 hidnplayr 1197
	jmp	.ack_processed
1514 hidnplayr 1198
 
1719 hidnplayr 1199
  .ack_c:
1514 hidnplayr 1200
 
1719 hidnplayr 1201
;;; TODO: 958
1514 hidnplayr 1202
 
1719 hidnplayr 1203
	jmp	.ack_processed
1514 hidnplayr 1204
 
1719 hidnplayr 1205
  .ack_la:
1514 hidnplayr 1206
 
1719 hidnplayr 1207
;;; TODO: 999
1514 hidnplayr 1208
 
1719 hidnplayr 1209
	jmp	.ack_processed
1514 hidnplayr 1210
 
1211
 
1719 hidnplayr 1212
  .ack_tw:
1514 hidnplayr 1213
 
1719 hidnplayr 1214
;;; TODO: 1010
1514 hidnplayr 1215
 
1719 hidnplayr 1216
	jmp	.ack_processed
1514 hidnplayr 1217
 
1218
 
1719 hidnplayr 1219
  .ack_processed:
1220
 
1221
	DEBUGF	1,"ack processed\n"
1222
 
1536 hidnplayr 1223
;----------------------------------------------
1224
; check if we need to update window information
1514 hidnplayr 1225
 
1226
	test	[edx + TCP_segment.Flags], TH_ACK
1227
	jz	.no_window_update
1228
 
1229
	mov	eax, [ebx + TCP_SOCKET.SND_WL1]
1230
	cmp	eax, [edx + TCP_segment.SequenceNumber]
1536 hidnplayr 1231
	jl	.update_window
1232
	jg	@f
1514 hidnplayr 1233
 
1234
	mov	eax, [ebx + TCP_SOCKET.SND_WL2]
1235
	cmp	eax, [edx + TCP_segment.AckNumber]
1536 hidnplayr 1236
	jl	.update_window
1237
	jg	.no_window_update
1238
       @@:
1514 hidnplayr 1239
 
1543 hidnplayr 1240
	mov	eax, [ebx + TCP_SOCKET.SND_WL2]
1536 hidnplayr 1241
	cmp	eax, [edx + TCP_segment.AckNumber]
1242
	jne	.no_window_update
1243
 
1244
	movzx	eax, [edx + TCP_segment.Window]
1514 hidnplayr 1245
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
1536 hidnplayr 1246
	jle	.no_window_update
1514 hidnplayr 1247
 
1536 hidnplayr 1248
  .update_window:
1514 hidnplayr 1249
 
1536 hidnplayr 1250
	DEBUGF	1,"Updating window\n"
1514 hidnplayr 1251
 
1536 hidnplayr 1252
;----------------------------------
1253
; Keep track of pure window updates
1254
 
1255
;        test    ecx, ecx
1256
;        jz      @f
1257
;
1258
;        mov     eax, [ebx + TCP_SOCKET.SND_WL2]
1259
;        cmp     eax, [edx + TCP_segment.AckNumber]
1260
;        jne     @f
1261
;
1262
;        ;; mov eax, tiwin
1263
;        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
1264
;        jle     @f
1265
;
1266
;        ;;; update stats
1267
;
1268
;       @@:
1269
 
1543 hidnplayr 1270
	mov	eax, dword [edx + TCP_segment.Window]
1514 hidnplayr 1271
	cmp	eax, [ebx + TCP_SOCKET.max_sndwnd]
1272
	jle	@f
1273
	mov	[ebx + TCP_SOCKET.max_sndwnd], eax
1274
       @@:
1275
	mov	[ebx + TCP_SOCKET.SND_WND], eax
1276
 
1536 hidnplayr 1277
	push	[edx + TCP_segment.SequenceNumber]
1278
	pop	[ebx + TCP_SOCKET.SND_WL1]
1514 hidnplayr 1279
 
1536 hidnplayr 1280
	push	[edx + TCP_segment.AckNumber]
1281
	pop	[ebx + TCP_SOCKET.SND_WL2]
1514 hidnplayr 1282
 
1283
	;;; needoutput = 1
1284
 
1285
  .no_window_update:
1286
 
1287
;-----------------
1288
; process URG flag
1289
 
1290
	test	[edx + TCP_segment.Flags], TH_URG
1291
	jz	.not_urgent
1292
 
1293
	cmp	[edx + TCP_segment.UrgentPointer], 0
1294
	jz	.not_urgent
1295
 
1296
	cmp	[ebx + TCP_SOCKET.t_state], TCB_TIMED_WAIT
1297
	je	.not_urgent
1298
 
1299
; Ignore bogus urgent offsets
1300
 
1301
	;;; 1040-1050
1302
 
1303
	movzx	eax, [edx + TCP_segment.UrgentPointer]
1533 hidnplayr 1304
	add	eax, [ebx + STREAM_SOCKET.rcv + RING_BUFFER.size]
1514 hidnplayr 1305
	cmp	eax, SOCKET_MAXDATA
1306
	jle	.not_urgent
1307
 
1308
	mov	[edx + TCP_segment.UrgentPointer], 0
1309
	and	[edx + TCP_segment.Flags], not (TH_URG)
1310
	jmp	.do_data
1311
 
1312
  .not_urgent:
1313
 
1314
;--------------------------------------
1315
; processing of received urgent pointer
1316
 
1529 hidnplayr 1317
	;;; TODO (1051-1093)
1514 hidnplayr 1318
 
1529 hidnplayr 1319
;--------------------------------
1320
; process the data in the segment
1514 hidnplayr 1321
 
1529 hidnplayr 1322
  .do_data:
1514 hidnplayr 1323
 
1534 hidnplayr 1324
	DEBUGF	1,"TCP: do data (%u)\n", ecx
1514 hidnplayr 1325
 
1326
	test	[edx + TCP_segment.Flags], TH_FIN
1529 hidnplayr 1327
	jnz	.process_fin
1514 hidnplayr 1328
 
1533 hidnplayr 1329
	cmp	[ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1
1514 hidnplayr 1330
	jge	.dont_do_data
1331
 
1533 hidnplayr 1332
	test	ecx, ecx
1333
	jz	.final_processing
1334
 
1514 hidnplayr 1335
	DEBUGF	1,"Processing data in segment\n"
1336
 
1533 hidnplayr 1337
;; TODO: check if data is in sequence !
1514 hidnplayr 1338
 
1533 hidnplayr 1339
	movzx	eax, [edx + TCP_segment.DataOffset]		;;; todo: remember this in.. edi ?
1340
	and	eax, 0xf0
1341
	shr	al, 2
1342
 
1343
	lea	esi, [edx + eax]
1344
 
1345
	or	[ebx + TCP_SOCKET.t_flags], TF_DELACK
1543 hidnplayr 1346
	add	[ebx + TCP_SOCKET.RCV_NXT], ecx
1533 hidnplayr 1347
 
1348
	lea	eax, [ebx + STREAM_SOCKET.rcv]
1349
	call	SOCKET_ring_write
1350
 
1351
	mov	eax, ebx
1352
	call	SOCKET_notify_owner
1353
 
1514 hidnplayr 1354
	jmp	.final_processing
1355
 
1356
 
1357
  .dont_do_data:
1358
 
1359
;---------------
1360
; FIN processing
1361
 
1362
  .process_fin:
1363
 
1364
	DEBUGF	1,"Processing FIN\n"
1365
 
1366
	mov	eax, [ebx + TCP_SOCKET.t_state]
1367
	shl	eax, 2
1368
	jmp	dword [eax + .FIN_sw_list]
1369
 
1370
  .FIN_sw_list:
1371
	dd	.no_fin 	;TCB_CLOSED
1372
	dd	.no_fin 	;TCB_LISTEN
1373
	dd	.no_fin 	;TCB_SYN_SENT
1533 hidnplayr 1374
	dd	.fin_syn_est	;TCB_SYN_RECEIVED
1375
	dd	.fin_syn_est	;TCB_ESTABLISHED
1514 hidnplayr 1376
	dd	.no_fin 	;TCB_CLOSE_WAIT
1533 hidnplayr 1377
	dd	.fin_wait1	;TCB_FIN_WAIT_1
1514 hidnplayr 1378
	dd	.no_fin 	;TCB_CLOSING
1379
	dd	.no_fin 	;TCB_LAST_ACK
1533 hidnplayr 1380
	dd	.fin_wait2	;TCB_FIN_WAIT_2
1381
	dd	.fin_timed	;TCB_TIMED_WAIT
1514 hidnplayr 1382
 
1383
 
1384
 
1533 hidnplayr 1385
  .fin_syn_est:
1514 hidnplayr 1386
 
1533 hidnplayr 1387
	jmp	.final_processing
1514 hidnplayr 1388
 
1533 hidnplayr 1389
  .fin_wait1:
1514 hidnplayr 1390
 
1533 hidnplayr 1391
	jmp	.final_processing
1514 hidnplayr 1392
 
1533 hidnplayr 1393
  .fin_wait2:
1514 hidnplayr 1394
 
1533 hidnplayr 1395
	jmp	.final_processing
1396
 
1397
  .fin_timed:
1398
 
1399
	jmp	.final_processing
1400
 
1514 hidnplayr 1401
  .no_fin:
1402
 
1403
;-----------------
1404
; Final processing
1405
 
1406
  .final_processing:
1407
 
1408
	DEBUGF	1,"Final processing\n"
1409
 
1533 hidnplayr 1410
	mov	[ebx + SOCKET.lock], 0
1411
 
1514 hidnplayr 1412
	;;; if debug enabled, output packet
1413
 
1719 hidnplayr 1414
	;test    needoutput, needoutput
1415
	;jz      .dumpit
1514 hidnplayr 1416
 
1417
	test	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1719 hidnplayr 1418
	jz	.dumpit
1514 hidnplayr 1419
 
1529 hidnplayr 1420
	DEBUGF	1,"ACK now!\n"
1421
 
1422
	push	ebx
1423
	mov	eax, ebx
1514 hidnplayr 1424
	call	TCP_output
1529 hidnplayr 1425
	pop	ebx
1514 hidnplayr 1426
 
1719 hidnplayr 1427
  .dumpit:
1428
 
1274 hidnplayr 1429
	call	kernel_free
1529 hidnplayr 1430
	add	esp, 4
1431
	ret
1274 hidnplayr 1432
 
1514 hidnplayr 1433
;------------------------------------------
1434
; Generate an ACK, droping incoming segment
1274 hidnplayr 1435
 
1514 hidnplayr 1436
align 4
1437
.drop_after_ack:
1274 hidnplayr 1438
 
1514 hidnplayr 1439
	DEBUGF	1,"Drop after ACK\n"
1274 hidnplayr 1440
 
1514 hidnplayr 1441
	test	[edx + TCP_segment.Flags], TH_RST
1442
	jnz	.drop
1274 hidnplayr 1443
 
1514 hidnplayr 1444
	and	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1274 hidnplayr 1445
 
1529 hidnplayr 1446
	push	ebx
1447
	mov	eax, ebx
1514 hidnplayr 1448
	call	TCP_output
1529 hidnplayr 1449
	pop	ebx
1318 hidnplayr 1450
 
1514 hidnplayr 1451
	call	kernel_free
1529 hidnplayr 1452
	add	esp, 4
1453
	ret
1274 hidnplayr 1454
 
1514 hidnplayr 1455
 
1456
;-------------------------------------------
1457
; Generate an RST, dropping incoming segment
1458
 
1459
align 4
1460
.drop_with_reset:
1461
 
1462
	DEBUGF	1,"Drop with reset\n"
1463
 
1464
	test	[edx + TCP_segment.Flags], TH_RST
1465
	jnz	.drop
1466
 
1467
	;;; if its a multicast/broadcast, also drop
1468
 
1469
	test	[edx + TCP_segment.Flags], TH_ACK
1470
	jnz	.respond_ack
1471
 
1472
	test	[edx + TCP_segment.Flags], TH_SYN
1473
	jnz	.respond_syn
1474
 
1475
	call	kernel_free
1529 hidnplayr 1476
	add	esp, 4
1477
	ret
1514 hidnplayr 1478
 
1479
  .respond_ack:
1480
 
1533 hidnplayr 1481
	mov	dl, TH_RST
1514 hidnplayr 1482
 
1533 hidnplayr 1483
	push	ebx
1529 hidnplayr 1484
	call	TCP_respond_segment
1533 hidnplayr 1485
	pop	ebx
1514 hidnplayr 1486
 
1487
	jmp	.destroy_new_socket
1488
 
1489
 
1490
  .respond_syn:
1491
 
1533 hidnplayr 1492
	mov	dl, TH_RST + TH_ACK
1514 hidnplayr 1493
 
1533 hidnplayr 1494
	push	ebx
1495
	call	TCP_respond_socket
1496
	pop	ebx
1514 hidnplayr 1497
 
1498
	jmp	.destroy_new_socket
1499
 
1500
;-----
1501
; Drop
1502
 
1503
align 4
1504
.drop:
1505
 
1506
	DEBUGF	1,"Dropping packet\n"
1507
 
1508
	;;;; If debugging options are enabled, output the packet somwhere
1509
 
1510
  .destroy_new_socket:
1511
 
1512
	;;;; kill the newly created socket
1513
 
1514
	call	kernel_free
1529 hidnplayr 1515
	add	esp, 4
1516
	ret
1514 hidnplayr 1517
 
1518
 
1519
 
1520
 
1521
 
1522
 
1523
;---------------------------
1524
;
1525
; TCP_pull_out_of_band
1526
;
1527
; IN:  eax =
1528
;      ebx = socket ptr
1529
;      edx = tcp packet ptr
1530
;
1531
; OUT: /
1532
;
1533
;---------------------------
1534
 
1535
align 4
1536
TCP_pull_out_of_band:
1537
 
1538
	DEBUGF	1,"TCP_pull_out_of_band\n"
1539
 
1540
	;;;; 1282-1305
1541
 
1318 hidnplayr 1542
	ret
1543
 
1544
 
1545
 
1546
;-----------------------------------------------------------------
1547
;
1514 hidnplayr 1548
; TCP_output
1318 hidnplayr 1549
;
1519 hidnplayr 1550
; IN:  eax = socket pointer
1514 hidnplayr 1551
;
1318 hidnplayr 1552
; OUT: /
1553
;
1554
;-----------------------------------------------------------------
1555
align 4
1514 hidnplayr 1556
TCP_output:
1318 hidnplayr 1557
 
1514 hidnplayr 1558
	DEBUGF 1,"TCP_output, socket: %x\n", eax
1318 hidnplayr 1559
 
1514 hidnplayr 1560
; We'll detect the length of the data to be transmitted, and flags to be used
1561
; If there is some data, or any critical controls to send (SYN / RST), then transmit
1562
; Otherwise, investigate further
1318 hidnplayr 1563
 
1514 hidnplayr 1564
	mov	ebx, [eax + TCP_SOCKET.SND_MAX]
1565
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1566
	jne	.not_idle
1318 hidnplayr 1567
 
1514 hidnplayr 1568
	mov	ebx, [eax + TCP_SOCKET.t_idle]
1569
	cmp	ebx, [eax + TCP_SOCKET.t_rxtcur]
1570
	jle	.not_idle
1318 hidnplayr 1571
 
1514 hidnplayr 1572
; We have been idle for a while and no ACKS are expected to clock out any data we send..
1573
; Slow start to get ack "clock" running again.
1318 hidnplayr 1574
 
1514 hidnplayr 1575
	mov	ebx, [eax + TCP_SOCKET.t_maxseg]
1576
	mov	[eax + TCP_SOCKET.SND_CWND], ebx
1318 hidnplayr 1577
 
1514 hidnplayr 1578
  .not_idle:
1579
  .again:
1580
	mov	ebx, [eax + TCP_SOCKET.SND_NXT] 	; calculate offset
1581
	sub	ebx, [eax + TCP_SOCKET.SND_UNA] 	;
1318 hidnplayr 1582
 
1514 hidnplayr 1583
	mov	ecx, [eax + TCP_SOCKET.SND_WND] 	; determine window
1584
	cmp	ecx, [eax + TCP_SOCKET.SND_CWND]	;
1585
	jl	@f					;
1586
	mov	ecx, [eax + TCP_SOCKET.SND_CWND]	;
1587
       @@:						;
1318 hidnplayr 1588
 
1529 hidnplayr 1589
	call	TCP_outflags	; in dl
1318 hidnplayr 1590
 
1514 hidnplayr 1591
; If in persist timeout with window of 0, send 1 byte.
1592
; Otherwise, if window is small but nonzero, and timer expired,
1593
; we will send what we can and go to transmit state
1318 hidnplayr 1594
 
1514 hidnplayr 1595
	test	[eax + TCP_SOCKET.t_force], -1
1596
	jz	.no_persist_timeout
1318 hidnplayr 1597
 
1514 hidnplayr 1598
	test	ecx, ecx
1599
	jnz	.no_zero_window
1255 hidnplayr 1600
 
1533 hidnplayr 1601
	cmp	ebx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1602
	jge	@f
1255 hidnplayr 1603
 
1514 hidnplayr 1604
	and	dl, not (TH_FIN)	  ; clear the FIN flag    ??? how can it be set before?
1255 hidnplayr 1605
 
1514 hidnplayr 1606
       @@:
1607
	inc	ecx
1608
	jmp	.no_persist_timeout
1255 hidnplayr 1609
 
1514 hidnplayr 1610
  .no_zero_window:
1254 hidnplayr 1611
 
1543 hidnplayr 1612
	mov	[eax + TCP_SOCKET.timer_persist], 0
1514 hidnplayr 1613
	mov	[eax + TCP_SOCKET.t_rxtshift], 0
1254 hidnplayr 1614
 
1514 hidnplayr 1615
  .no_persist_timeout:
1159 hidnplayr 1616
 
1514 hidnplayr 1617
;;;106
1159 hidnplayr 1618
 
1533 hidnplayr 1619
	mov	esi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1620
	cmp	esi, ecx
1621
	jl	@f
1622
	mov	esi, ecx
1623
       @@:
1624
	sub	esi, ebx
1254 hidnplayr 1625
 
1514 hidnplayr 1626
	cmp	esi, -1
1627
	jne	.not_minus_one
1159 hidnplayr 1628
 
1514 hidnplayr 1629
; If FIN has been set, but not ACKed, and we havent been called to retransmit,
1630
; len (esi) will be -1
1631
; Otherwise, window shrank after we sent into it.
1632
; If window shrank to 0, cancel pending retransmit and pull SND_NXT back to (closed) window
1633
; We will enter persist state below.
1634
; If window didn't close completely, just wait for an ACK
1159 hidnplayr 1635
 
1514 hidnplayr 1636
	xor	esi, esi
1159 hidnplayr 1637
 
1514 hidnplayr 1638
	test	ecx, ecx
1639
	jnz	@f
1159 hidnplayr 1640
 
1529 hidnplayr 1641
	mov	[eax + TCP_SOCKET.timer_retransmission], 0   ; cancel retransmit
1274 hidnplayr 1642
 
1514 hidnplayr 1643
	push	[eax + TCP_SOCKET.SND_UNA]
1644
	pop	[eax + TCP_SOCKET.SND_NXT]
1645
       @@:
1254 hidnplayr 1646
 
1514 hidnplayr 1647
  .not_minus_one:
1254 hidnplayr 1648
 
1514 hidnplayr 1649
;;; 124
1159 hidnplayr 1650
 
1514 hidnplayr 1651
	cmp	esi, [eax + TCP_SOCKET.t_maxseg]
1652
	jle	@f
1274 hidnplayr 1653
 
1514 hidnplayr 1654
	mov	esi, [eax + TCP_SOCKET.t_maxseg]
1655
	;sendalot = 1
1274 hidnplayr 1656
 
1514 hidnplayr 1657
       @@:
1274 hidnplayr 1658
 
1514 hidnplayr 1659
;;; 128
1274 hidnplayr 1660
 
1514 hidnplayr 1661
	mov	edi, [eax + TCP_SOCKET.SND_NXT]
1662
	add	edi, esi	; len
1663
	sub	edi, [eax + TCP_SOCKET.SND_UNA]
1533 hidnplayr 1664
	add	edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1665
	cmp	edi, 0
1666
	jle	@f
1274 hidnplayr 1667
 
1514 hidnplayr 1668
	and	dl, not (TH_FIN)	  ; clear the FIN flag
1159 hidnplayr 1669
 
1514 hidnplayr 1670
       @@:
1159 hidnplayr 1671
 
1672
 
1529 hidnplayr 1673
; set ecx to space available in receive buffer
1674
; From now on, ecx will be the window we advertise to the other end
1159 hidnplayr 1675
 
1529 hidnplayr 1676
	mov	ecx, SOCKET_MAXDATA
1533 hidnplayr 1677
	sub	ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
1159 hidnplayr 1678
 
1514 hidnplayr 1679
;------------------------------
1680
; Sender silly window avoidance
1159 hidnplayr 1681
 
1529 hidnplayr 1682
	cmp	ecx, [eax + TCP_SOCKET.t_maxseg]
1514 hidnplayr 1683
	je	.send
1274 hidnplayr 1684
 
1514 hidnplayr 1685
;;; TODO: 144-145
1274 hidnplayr 1686
 
1514 hidnplayr 1687
	test	[eax + TCP_SOCKET.t_force], -1
1688
	jnz	.send
1274 hidnplayr 1689
 
1529 hidnplayr 1690
	mov	ebx, [eax + TCP_SOCKET.max_sndwnd]
1691
	shr	ebx, 1
1692
	cmp	ecx, ebx
1693
	jge	.send
1274 hidnplayr 1694
 
1529 hidnplayr 1695
	mov	ebx, [eax + TCP_SOCKET.SND_NXT]
1696
	cmp	ebx, [eax + TCP_SOCKET.SND_MAX]
1697
	jl	.send
1254 hidnplayr 1698
 
1514 hidnplayr 1699
;----------------------------------------
1700
; Check if a window update should be sent
1159 hidnplayr 1701
 
1529 hidnplayr 1702
	test	ecx, ecx	; window
1703
	jz	.no_window
1159 hidnplayr 1704
 
1514 hidnplayr 1705
;;; TODO 154-172
1159 hidnplayr 1706
 
1514 hidnplayr 1707
  .no_window:
1159 hidnplayr 1708
 
1514 hidnplayr 1709
;--------------------------
1710
; Should a segment be sent?
1159 hidnplayr 1711
 
1534 hidnplayr 1712
	test	[eax + TCP_SOCKET.t_flags], TF_ACKNOW
1514 hidnplayr 1713
	jnz	.send
1159 hidnplayr 1714
 
1514 hidnplayr 1715
	test	dl, TH_SYN + TH_RST
1716
	jnz	.send
1159 hidnplayr 1717
 
1534 hidnplayr 1718
	mov	ebx, [eax + TCP_SOCKET.SND_UP]
1719
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1514 hidnplayr 1720
	jg	.send
1249 hidnplayr 1721
 
1514 hidnplayr 1722
	test	dl, TH_FIN
1723
	jz	.enter_persist
1318 hidnplayr 1724
 
1534 hidnplayr 1725
	test	[eax + TCP_SOCKET.t_flags], TF_SENTFIN
1514 hidnplayr 1726
	jnz	.send
1254 hidnplayr 1727
 
1534 hidnplayr 1728
	mov	ebx, [eax + TCP_SOCKET.SND_NXT]
1729
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1514 hidnplayr 1730
	je	.send
1254 hidnplayr 1731
 
1514 hidnplayr 1732
;--------------------
1733
; Enter persist state
1318 hidnplayr 1734
 
1514 hidnplayr 1735
  .enter_persist:
1318 hidnplayr 1736
 
1519 hidnplayr 1737
	DEBUGF	1,"Entering persist state\n"
1318 hidnplayr 1738
 
1514 hidnplayr 1739
;--------------------------------------
1740
; No reason to send a segment, just ret
1318 hidnplayr 1741
 
1514 hidnplayr 1742
	DEBUGF	1,"No reason to send a segment\n"
1318 hidnplayr 1743
 
1514 hidnplayr 1744
	ret
1318 hidnplayr 1745
 
1746
 
1514 hidnplayr 1747
;-----------------------------------------------
1748
;
1749
; Send a segment
1750
;
1529 hidnplayr 1751
; eax = socket pointer
1514 hidnplayr 1752
;  dl = flags
1753
;
1754
;-----------------------------------------------
1318 hidnplayr 1755
 
1529 hidnplayr 1756
  .send:
1318 hidnplayr 1757
 
1514 hidnplayr 1758
	DEBUGF	1,"Preparing to send a segment\n"
1318 hidnplayr 1759
 
1529 hidnplayr 1760
	mov	edi, TCP_segment.Data	; edi will contain headersize
1318 hidnplayr 1761
 
1529 hidnplayr 1762
	sub	esp, 8			; create some space on stack
1763
	push	eax			; save this too..
1764
 
1514 hidnplayr 1765
;------------------------------------
1766
; Send options with first SYN segment
1318 hidnplayr 1767
 
1514 hidnplayr 1768
	test	dl, TH_SYN
1769
	jz	.no_options
1318 hidnplayr 1770
 
1529 hidnplayr 1771
	push	[eax + TCP_SOCKET.ISS]
1772
	pop	[eax + TCP_SOCKET.SND_NXT]
1318 hidnplayr 1773
 
1529 hidnplayr 1774
	test	[eax + TCP_SOCKET.t_flags], TF_NOOPT
1514 hidnplayr 1775
	jnz	.no_options
1318 hidnplayr 1776
 
1529 hidnplayr 1777
	mov	ecx, 1460
1778
	or	ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
1779
	bswap	ecx
1780
	push	ecx
1781
	add	di, 4
1514 hidnplayr 1782
 
1529 hidnplayr 1783
	test	[eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
1514 hidnplayr 1784
	jz	.no_syn
1785
 
1786
	test	dl, TH_ACK
1787
	jnz	.scale_opt
1788
 
1529 hidnplayr 1789
	test	[eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
1514 hidnplayr 1790
	jz	.no_syn
1791
 
1792
  .scale_opt:
1529 hidnplayr 1793
	movzx	ecx, byte [eax + TCP_SOCKET.request_r_scale]
1794
	or	ecx, TCP_OPT_WINDOW shl 24 + 4 shl 16 + TCP_OPT_NOP shl 8
1795
	bswap	ecx
1796
	pushd	ecx
1514 hidnplayr 1797
	add	di, 4
1159 hidnplayr 1798
 
1514 hidnplayr 1799
  .no_syn:
1159 hidnplayr 1800
 
1514 hidnplayr 1801
;------------------------------------
1802
; Make the timestamp option if needed
1159 hidnplayr 1803
 
1529 hidnplayr 1804
	test	[eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
1514 hidnplayr 1805
	jz	.no_timestamp
1159 hidnplayr 1806
 
1514 hidnplayr 1807
	test	dl, TH_RST
1808
	jnz	.no_timestamp
1809
 
1810
	test	dl, TH_ACK
1811
	jz	.timestamp
1812
 
1529 hidnplayr 1813
	test	[eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
1514 hidnplayr 1814
	jz	.no_timestamp
1815
 
1816
  .timestamp:
1529 hidnplayr 1817
	mov	esi, [timer_ticks]
1818
	bswap	esi
1819
	push	esi
1514 hidnplayr 1820
	pushw	0
1529 hidnplayr 1821
	pushd	TCP_OPT_TIMESTAMP + 10 shl 8 + TCP_OPT_NOP shl 16 + TCP_OPT_NOP shl 24
1514 hidnplayr 1822
	add	di, 10
1823
 
1824
  .no_timestamp:
1825
	;; TODO: check if we dont exceed the max segment size
1826
 
1827
  .no_options:
1529 hidnplayr 1828
	; eax = socket ptr
1829
	; edx = flags
1830
	; ecx = data size
1831
	; edi = header size
1832
	; esi = snd ring buff ptr
1514 hidnplayr 1833
 
1533 hidnplayr 1834
	mov	ecx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1835
	cmp	ecx, [eax + TCP_SOCKET.t_maxseg]			;;; right?
1836
	jle	@f
1837
	mov	ecx, [eax + TCP_SOCKET.t_maxseg]
1838
       @@:
1514 hidnplayr 1839
	add	ecx, edi	; total TCP segment size
1840
 
1529 hidnplayr 1841
; Start by pushing all TCP header values in reverse order on stack
1842
; (essentially, creating the tcp header!)
1514 hidnplayr 1843
 
1529 hidnplayr 1844
	pushw	0	;        .UrgentPointer          dw ?
1845
	pushw	0	;        .Checksum               dw ?
1846
	pushw	0x00a0	;        .Window                 dw ?    ;;;;;;;
1847
	shl	edi, 2	;        .DataOffset             db ?  only 4 left-most bits
1848
	shl	dx, 8
1849
	or	dx, di	;        .Flags                  db ?
1850
	pushw	dx
1851
	shr	edi, 2	;        .DataOffset             db ? ;;;;
1514 hidnplayr 1852
 
1529 hidnplayr 1853
	push	[eax + TCP_SOCKET.RCV_NXT]	;        .AckNumber              dd ?
1543 hidnplayr 1854
	ntohd	[esp]
1159 hidnplayr 1855
 
1529 hidnplayr 1856
	push	[eax + TCP_SOCKET.SND_NXT]	;        .SequenceNumber         dd ?
1543 hidnplayr 1857
	ntohd	[esp]
1159 hidnplayr 1858
 
1529 hidnplayr 1859
	push	[eax + TCP_SOCKET.RemotePort]	;        .DestinationPort        dw ?
1543 hidnplayr 1860
	ntohw	[esp]
1249 hidnplayr 1861
 
1529 hidnplayr 1862
	push	[eax + TCP_SOCKET.LocalPort]	;        .SourcePort             dw ?
1543 hidnplayr 1863
	ntohw	[esp]
1274 hidnplayr 1864
 
1533 hidnplayr 1865
	push	edi		; header size
1274 hidnplayr 1866
 
1529 hidnplayr 1867
; Create the IP packet
1868
	mov	ebx, [eax + IP_SOCKET.LocalIP]	; source ip
1869
	mov	eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
1870
	mov	di, IP_PROTO_TCP shl 8 + 128
1871
	call	IPv4_output
1872
	jz	.fail
1274 hidnplayr 1873
 
1529 hidnplayr 1874
;-----------------------------------------
1875
; Move TCP header from stack to TCP packet
1274 hidnplayr 1876
 
1533 hidnplayr 1877
	push	ecx
1878
	mov	ecx, [esp+4]
1879
	lea	esi, [esp+4+4]
1529 hidnplayr 1880
	shr	ecx, 2
1881
	rep	movsd
1533 hidnplayr 1882
	pop	ecx		; full TCP packet size
1274 hidnplayr 1883
 
1533 hidnplayr 1884
	pop	esi		; headersize
1885
	add	esp, esi
1254 hidnplayr 1886
 
1533 hidnplayr 1887
	mov	[esp + 4], eax		; packet ptr
1530 hidnplayr 1888
	mov	[esp + 4+4], edx	; packet size
1254 hidnplayr 1889
 
1533 hidnplayr 1890
	mov	edx, edi		; begin of data
1891
	sub	edx, esi		; begin of packet (edi = begin of data)
1892
	push	ecx
1893
	sub	ecx, esi		; data size
1159 hidnplayr 1894
 
1514 hidnplayr 1895
;--------------
1896
; Copy the data
1159 hidnplayr 1897
 
1529 hidnplayr 1898
; eax = ptr to ring struct
1899
; ecx = buffer size
1900
; edi = ptr to buffer
1249 hidnplayr 1901
 
1536 hidnplayr 1902
;        test    ecx, ecx
1533 hidnplayr 1903
	mov	eax, [esp+4]		  ; socket ptr
1536 hidnplayr 1904
	add	[eax + TCP_SOCKET.SND_NXT], ecx
1905
	add	eax, STREAM_SOCKET.snd
1533 hidnplayr 1906
	push	edx
1529 hidnplayr 1907
	call	SOCKET_ring_read
1536 hidnplayr 1908
	pop	esi
1909
	pop	ecx
1529 hidnplayr 1910
	pop	eax
1254 hidnplayr 1911
 
1533 hidnplayr 1912
	test	[esi + TCP_segment.Flags], TH_SYN + TH_FIN
1913
	jz	@f
1914
	inc	[eax + TCP_SOCKET.SND_NXT]
1915
	;;; TODO: update sentfin flag
1916
       @@:
1254 hidnplayr 1917
 
1533 hidnplayr 1918
	mov	edx, [eax + TCP_SOCKET.SND_NXT]
1919
	cmp	edx, [eax + TCP_SOCKET.SND_MAX]
1920
	jle	@f
1921
	mov	[eax + TCP_SOCKET.SND_MAX], edx
1922
 
1923
	;;;; TODO: time transmission (420)
1924
       @@:
1925
 
1926
	;;; TODO: set retransmission timer
1927
 
1928
;--------------------
1929
; Create the checksum
1930
 
1529 hidnplayr 1931
	DEBUGF	1,"checksum: ptr=%x size=%u\n", esi, ecx
1159 hidnplayr 1932
 
1529 hidnplayr 1933
	TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
1934
	mov	[esi+TCP_segment.Checksum], dx
1935
 
1514 hidnplayr 1936
;----------------
1937
; Send the packet
1159 hidnplayr 1938
 
1529 hidnplayr 1939
	DEBUGF	1,"Sending TCP Packet to device %x\n", ebx
1940
	call	[ebx + NET_DEVICE.transmit]
1941
	ret
1159 hidnplayr 1942
 
1514 hidnplayr 1943
 
1529 hidnplayr 1944
  .fail:
1945
	pop	ecx
1946
	add	esp, ecx
1536 hidnplayr 1947
	add	esp, 4+8
1529 hidnplayr 1948
	DEBUGF 1,"TCP_output: failed\n"
1159 hidnplayr 1949
	ret
1950
 
1529 hidnplayr 1951
 
1952
 
1514 hidnplayr 1953
;-------------------------
1954
;
1955
; TCP_outflags
1956
;
1957
;  IN:  eax = socket ptr
1958
;
1959
;  OUT: edx = flags
1960
;
1961
;-------------------------
1249 hidnplayr 1962
align 4
1514 hidnplayr 1963
TCP_outflags:
1254 hidnplayr 1964
 
1514 hidnplayr 1965
	mov	edx, [eax + TCP_SOCKET.t_state]
1966
	movzx	edx, byte [edx + .flaglist]
1254 hidnplayr 1967
 
1514 hidnplayr 1968
	DEBUGF	1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
1969
 
1159 hidnplayr 1970
	ret
1971
 
1514 hidnplayr 1972
  .flaglist:
1159 hidnplayr 1973
 
1514 hidnplayr 1974
	db	TH_RST + TH_ACK 	; TCB_CLOSED
1975
	db	0			; TCB_LISTEN
1976
	db	TH_SYN			; TCB_SYN_SENT
1977
	db	TH_SYN + TH_ACK 	; TCB_SYN_RECEIVED
1978
	db		 TH_ACK 	; TCB_ESTABLISHED
1979
	db		 TH_ACK 	; TCB_CLOSE_WAIT
1980
	db	TH_SYN + TH_ACK 	; TCB_FIN_WAIT_1
1981
	db	TH_SYN + TH_ACK 	; TCB_CLOSING
1982
	db	TH_SYN + TH_ACK 	; TCB_LAST_ACK
1983
	db		 TH_ACK 	; TCB_FIN_WAIT_2
1984
	db		 TH_ACK 	; TCB_TIMED_WAIT
1249 hidnplayr 1985
 
1514 hidnplayr 1986
 
1529 hidnplayr 1987
 
1988
 
1514 hidnplayr 1989
;-------------------------
1990
;
1991
; TCP_drop
1992
;
1993
;  IN:  eax = socket ptr
1716 hidnplayr 1994
;       ebx = error number
1514 hidnplayr 1995
;
1716 hidnplayr 1996
;  OUT: eax = socket ptr
1514 hidnplayr 1997
;
1998
;-------------------------
1249 hidnplayr 1999
align 4
1514 hidnplayr 2000
TCP_drop:
1254 hidnplayr 2001
 
1514 hidnplayr 2002
	DEBUGF	1,"TCP_drop\n"
1254 hidnplayr 2003
 
1716 hidnplayr 2004
	cmp	[eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
2005
	jl	.no_syn_received
1159 hidnplayr 2006
 
1514 hidnplayr 2007
	mov	[eax + TCP_SOCKET.t_state], TCB_CLOSED
1159 hidnplayr 2008
 
1514 hidnplayr 2009
	call	TCP_output
1254 hidnplayr 2010
 
1716 hidnplayr 2011
;;; TODO: update stats
1514 hidnplayr 2012
 
1716 hidnplayr 2013
	jmp	TCP_close
2014
 
2015
  .no_syn_received:
2016
 
2017
;;; TODO: update stats
2018
 
2019
;;; TODO: check if error code is "Connection timed out' and handle accordingly
2020
 
2021
	mov	[eax + SOCKET.errorcode], ebx
2022
 
2023
	jmp	TCP_close
2024
 
2025
 
2026
;-------------------------
2027
;
2028
; TCP_close
2029
;
2030
;  IN:  eax = socket ptr
2031
;  OUT: eax = socket ptr
2032
;
2033
;-------------------------
2034
align 4
2035
TCP_close:
2036
 
1719 hidnplayr 2037
	DEBUGF	1,"TCP_close\n"
2038
 
1716 hidnplayr 2039
;;; TODO: update RTT and mean deviation
2040
;;; TODO: update slow start threshold
2041
;;; TODO: release connection resources
2042
 
1719 hidnplayr 2043
; Now, mark the socket as being disconnected
2044
 
2045
	mov	[eax + SOCKET.state], 0 ;;; FIXME
2046
 
1159 hidnplayr 2047
	ret
2048
 
2049
 
1254 hidnplayr 2050
 
2051
 
1514 hidnplayr 2052
;---------------------------------------
2053
;
1519 hidnplayr 2054
; The easy way to send an ACK/RST/keepalive segment
1514 hidnplayr 2055
;
1529 hidnplayr 2056
; TCP_respond_socket:
2057
;
2058
;  IN:  ebx = socket ptr
1519 hidnplayr 2059
;        cl = flags
1514 hidnplayr 2060
;
1529 hidnplayr 2061
;--------------------------------------
1514 hidnplayr 2062
align 4
1529 hidnplayr 2063
TCP_respond_socket:
1254 hidnplayr 2064
 
1529 hidnplayr 2065
	DEBUGF	1,"TCP_respond_socket\n"
1159 hidnplayr 2066
 
1519 hidnplayr 2067
;---------------------
2068
; Create the IP packet
2069
 
1529 hidnplayr 2070
	push	cx ebx
2071
	mov	eax, [ebx + IP_SOCKET.RemoteIP]
2072
	mov	ebx, [ebx + IP_SOCKET.LocalIP]
1519 hidnplayr 2073
	mov	ecx, TCP_segment.Data
1529 hidnplayr 2074
	mov	di , IP_PROTO_TCP shl 8 + 128
2075
	call	IPv4_output
1519 hidnplayr 2076
	test	edi, edi
2077
	jz	.error
1529 hidnplayr 2078
	pop	esi cx
2079
	push	edx eax
1519 hidnplayr 2080
 
1529 hidnplayr 2081
;-----------------------------------------------
2082
; Fill in the TCP header by using the socket ptr
1519 hidnplayr 2083
 
1529 hidnplayr 2084
	mov	ax, [esi + TCP_SOCKET.LocalPort]
2085
	rol	ax, 8
2086
	stosw
2087
	mov	ax, [esi + TCP_SOCKET.RemotePort]
2088
	rol	ax, 8
2089
	stosw
2090
	mov	eax, [esi + TCP_SOCKET.SND_NXT]
2091
	bswap	eax
2092
	stosd
2093
	mov	eax, [esi + TCP_SOCKET.RCV_NXT]
2094
	bswap	eax
2095
	stosd
2096
	mov	al, 0x50	; Dataoffset: 20 bytes
2097
	stosb
2098
	mov	al, cl
2099
	stosb
2100
	mov	ax, [esi + TCP_SOCKET.RCV_WND]
2101
	rol	ax, 8
2102
	stosw			; window
2103
	xor	eax, eax
2104
	stosd			; checksum + urgentpointer
1519 hidnplayr 2105
 
2106
;---------------------
2107
; Fill in the checksum
2108
 
2109
  .checksum:
1529 hidnplayr 2110
	sub	edi, TCP_segment.Data
2111
	mov	ecx, TCP_segment.Data
2112
	xchg	esi, edi
2113
	TCP_checksum (edi + IP_SOCKET.LocalIP), (esi + IP_SOCKET.RemoteIP)
2114
	mov	[esi+TCP_segment.Checksum], dx
1519 hidnplayr 2115
 
2116
;--------------------
2117
; And send the segment
2118
 
2119
	call	[ebx + NET_DEVICE.transmit]
1159 hidnplayr 2120
	ret
2121
 
1519 hidnplayr 2122
  .error:
1529 hidnplayr 2123
	DEBUGF	1,"TCP_respond failed\n"
2124
	add	esp, 2+4
1159 hidnplayr 2125
 
1519 hidnplayr 2126
	ret
1514 hidnplayr 2127
 
1529 hidnplayr 2128
 
2129
 
2130
;-------------------------
2131
; TCP_respond.segment:
2132
;
2133
;  IN:  edx = segment ptr (a previously received segment)
2134
;        cl = flags
2135
 
2136
align 4
2137
TCP_respond_segment:
2138
 
2139
	DEBUGF	1,"TCP_respond_segment\n"
2140
 
2141
;---------------------
2142
; Create the IP packet
2143
 
2144
	push	cx edx
2145
	mov	ebx, [edx - 20 + IPv4_Packet.SourceAddress]	 ;;;; and what if ip packet had options?!
2146
	mov	eax, [edx - 20 + IPv4_Packet.DestinationAddress]   ;;;
2147
	mov	ecx, TCP_segment.Data
2148
	mov	di , IP_PROTO_TCP shl 8 + 128
2149
	call	IPv4_output
2150
	jz	.error
1533 hidnplayr 2151
	pop	esi cx
1529 hidnplayr 2152
 
2153
	push	edx eax
2154
 
1519 hidnplayr 2155
;---------------------------------------------------
2156
; Fill in the TCP header by using a received segment
2157
 
2158
	mov	ax, [esi + TCP_segment.DestinationPort]
2159
	rol	ax, 8
2160
	stosw
2161
	mov	ax, [esi + TCP_segment.SourcePort]
2162
	rol	ax, 8
2163
	stosw
2164
	mov	eax, [esi + TCP_segment.AckNumber]
2165
	bswap	eax
2166
	stosd
2167
	xor	eax, eax
2168
	stosd
2169
	mov	al, 0x50	; Dataoffset: 20 bytes
2170
	stosb
2171
	mov	al, cl
2172
	stosb
2173
	mov	ax, 1280
2174
	rol	ax, 8
2175
	stosw			; window
2176
	xor	eax, eax
2177
	stosd			; checksum + urgentpointer
2178
 
1529 hidnplayr 2179
;---------------------
2180
; Fill in the checksum
1519 hidnplayr 2181
 
1529 hidnplayr 2182
  .checksum:
2183
	lea	esi, [edi - TCP_segment.Data]
2184
	mov	ecx, TCP_segment.Data
2185
	TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress)
2186
	mov	[esi+TCP_segment.Checksum], dx
1519 hidnplayr 2187
 
1529 hidnplayr 2188
;--------------------
2189
; And send the segment
1519 hidnplayr 2190
 
1529 hidnplayr 2191
	call	[ebx + NET_DEVICE.transmit]
2192
	ret
1519 hidnplayr 2193
 
1529 hidnplayr 2194
  .error:
2195
	DEBUGF	1,"TCP_respond failed\n"
2196
	add	esp, 2+4
1519 hidnplayr 2197
 
2198
	ret
2199
 
2200
 
2201
 
1254 hidnplayr 2202
 
2203
;---------------------------------------------------------------------------
2204
;
2205
; TCP_API
2206
;
2207
; This function is called by system function 75
2208
;
2209
; IN:  subfunction number in bl
2210
;      device number in bh
2211
;      ecx, edx, .. depends on subfunction
2212
;
2213
; OUT:
2214
;
2215
;---------------------------------------------------------------------------
2216
align 4
2217
TCP_API:
2218
 
2219
	movzx	eax, bh
2220
	shl	eax, 2
2221
 
2222
	test	bl, bl
2223
	jz	.packets_tx	; 0
2224
	dec	bl
2225
	jz	.packets_rx	; 1
2226
 
2227
.error:
2228
	mov	eax, -1
2229
	ret
2230
 
2231
.packets_tx:
1514 hidnplayr 2232
	add	eax, TCP_segments_tx
1254 hidnplayr 2233
	mov	eax, [eax]
2234
	ret
2235
 
2236
.packets_rx:
1514 hidnplayr 2237
	add	eax, TCP_segments_rx
1254 hidnplayr 2238
	mov	eax, [eax]
2239
	ret