Subversion Repositories Kolibri OS

Rev

Details | 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: 1716 $
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
575
 
1543 hidnplayr 576
	mov	eax, dword [edx + TCP_segment.Window]
1536 hidnplayr 577
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
578
	jne	.not_uni_xfer
1514 hidnplayr 579
 
580
	mov	eax, [ebx + TCP_SOCKET.SND_NXT]
581
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
582
	jne	.not_uni_xfer
583
 
584
;---------------------------------------
585
; check if we are sender in the uni-xfer
586
 
587
; If the following 4 conditions are all true, this segment is a pure ACK.
588
;
1529 hidnplayr 589
; - The segment contains no data.
590
	test	ecx, ecx
1514 hidnplayr 591
	jnz	.not_sender
1274 hidnplayr 592
 
1529 hidnplayr 593
; - The congestion window is greater than or equal to the current send window.
1514 hidnplayr 594
;     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.
595
	mov	eax, [ebx + TCP_SOCKET.SND_CWND]
596
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
597
	jl	.not_uni_xfer
1318 hidnplayr 598
 
1529 hidnplayr 599
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
1534 hidnplayr 600
	mov	eax, [edx + TCP_segment.AckNumber]
601
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
1529 hidnplayr 602
	jg	.not_uni_xfer
603
 
604
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
1534 hidnplayr 605
	sub	eax, [ebx + TCP_SOCKET.SND_UNA]
1529 hidnplayr 606
	jle	.not_uni_xfer
607
 
1514 hidnplayr 608
	DEBUGF	1,"Header prediction: we are sender\n"
1274 hidnplayr 609
 
1514 hidnplayr 610
;---------------------------------
611
; Packet is a pure ACK, process it
1274 hidnplayr 612
 
1514 hidnplayr 613
; Update RTT estimators
1159 hidnplayr 614
 
1514 hidnplayr 615
; Delete acknowledged bytes from send buffer
1536 hidnplayr 616
	mov	ecx, eax
1533 hidnplayr 617
	lea	eax, [ebx + STREAM_SOCKET.snd]
1529 hidnplayr 618
	call	SOCKET_ring_free
619
 
1536 hidnplayr 620
; update window pointers
621
	mov	eax, [edx + TCP_segment.AckNumber]
622
	dec	eax
623
	mov	[ebx + TCP_SOCKET.SND_WL1], eax
624
 
1514 hidnplayr 625
; Stop retransmit timer
1519 hidnplayr 626
	mov	[ebx + TCP_SOCKET.timer_ack], 0
1159 hidnplayr 627
 
1514 hidnplayr 628
; Awaken waiting processes
1519 hidnplayr 629
	mov	eax, ebx
630
	call	SOCKET_notify_owner
1318 hidnplayr 631
 
1536 hidnplayr 632
;; Generate more output
633
;;        mov     eax, ebx
634
;;        call    TCP_output
635
;;
636
;;        jmp     .drop
637
	jmp	.step6
1254 hidnplayr 638
 
1514 hidnplayr 639
;-------------------------------------------------
640
; maybe we are the receiver in the uni-xfer then..
641
 
642
  .not_sender:
1529 hidnplayr 643
; - The amount of data in the segment is greater than 0 (data count is in ecx)
1514 hidnplayr 644
 
1529 hidnplayr 645
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
1514 hidnplayr 646
	mov	eax, [edx + TCP_segment.AckNumber]
647
	cmp	eax, [ebx + TCP_SOCKET.SND_UNA]
648
	jne	.not_uni_xfer
649
 
1529 hidnplayr 650
; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp). ;;;;;;;
1514 hidnplayr 651
 
652
	jnz	.not_uni_xfer
653
 
654
;-------------------------------------
655
; Complete processing of received data
656
 
657
	DEBUGF	1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx
658
 
1529 hidnplayr 659
	add	esi, edx
1533 hidnplayr 660
	lea	eax, [ebx + STREAM_SOCKET.rcv]
661
	call	SOCKET_ring_write			; Add the data to the socket buffer
1514 hidnplayr 662
 
1533 hidnplayr 663
	mov	eax, ebx
664
	call	SOCKET_notify_owner
665
 
1529 hidnplayr 666
	add	[ebx + TCP_SOCKET.RCV_NXT], ecx 	; Update sequence number with number of bytes we have copied
667
	or	[ebx + TCP_SOCKET.t_flags], TF_DELACK	; Set delayed ack flag
1514 hidnplayr 668
 
669
	jmp	.drop
670
 
671
;----------------------------------------------------
1529 hidnplayr 672
; Header prediction failed, doing it the slow way..     ;;;;; current implementation of header prediction destroys some regs (ecx) !!
1514 hidnplayr 673
 
674
  .not_uni_xfer:
675
 
1533 hidnplayr 676
	DEBUGF	1,"Header prediction failed\n"		; time to do it the "slow" way :)
1514 hidnplayr 677
 
678
;------------------------------
679
; Calculate receive window size
680
 
681
	;;;;
682
 
1529 hidnplayr 683
	cmp	[ebx + TCP_SOCKET.t_state], TCB_LISTEN
1514 hidnplayr 684
	je	.LISTEN
685
 
1529 hidnplayr 686
	cmp	[ebx + TCP_SOCKET.t_state], TCB_SYN_SENT
1514 hidnplayr 687
	je	.SYN_SENT
688
 
689
;--------------------------------------------
690
; Protection Against Wrapped Sequence Numbers
691
 
1533 hidnplayr 692
; First, check if timestamp is present
1514 hidnplayr 693
 
694
;;;; TODO
695
 
696
; Then, check if at least some bytes of data are within window
697
 
698
;;;; TODO
699
 
700
	jmp	.trim_then_step6
701
 
1529 hidnplayr 702
;-------------
703
; Passive Open
704
 
1249 hidnplayr 705
align 4
1514 hidnplayr 706
.LISTEN:
1196 hidnplayr 707
 
1514 hidnplayr 708
	DEBUGF	1,"TCP state: listen\n"
1159 hidnplayr 709
 
1543 hidnplayr 710
	test	[edx + TCP_segment.Flags], TH_RST	;;; TODO: kill new socket on error
1514 hidnplayr 711
	jnz	.drop
1159 hidnplayr 712
 
1514 hidnplayr 713
	test	[edx + TCP_segment.Flags], TH_ACK
714
	jnz	.drop_with_reset
1159 hidnplayr 715
 
1514 hidnplayr 716
	test	[edx + TCP_segment.Flags], TH_SYN
717
	jz	.drop
1159 hidnplayr 718
 
1533 hidnplayr 719
 
1514 hidnplayr 720
	; TODO: check if it's a broadcast or multicast, and drop if so
1159 hidnplayr 721
 
1529 hidnplayr 722
;-----------------------
723
; Fill in some variables
1514 hidnplayr 724
 
1529 hidnplayr 725
	add	[TCP_sequence_num], 64000
1514 hidnplayr 726
 
1529 hidnplayr 727
	push	[edx + TCP_segment.SourcePort]
728
	pop	[eax + TCP_SOCKET.RemotePort]
1514 hidnplayr 729
 
1529 hidnplayr 730
	push	[edx + TCP_segment.SequenceNumber]
731
	pop	[eax + TCP_SOCKET.IRS]
1159 hidnplayr 732
 
1529 hidnplayr 733
	push	[eax + TCP_SOCKET.ISS]
734
	pop	[eax + TCP_SOCKET.SND_NXT]
1159 hidnplayr 735
 
1543 hidnplayr 736
	TCP_sendseqinit eax
737
	TCP_rcvseqinit eax
738
 
1529 hidnplayr 739
	mov	[eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
740
	mov	[eax + TCP_SOCKET.t_flags], TF_ACKNOW
1543 hidnplayr 741
	mov	[eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval  ;;;; macro
1159 hidnplayr 742
 
1543 hidnplayr 743
	add	eax, STREAM_SOCKET.snd
744
	call	SOCKET_ring_create
745
 
746
	add	eax, STREAM_SOCKET.rcv - STREAM_SOCKET.snd
747
	call	SOCKET_ring_create
748
 
749
	sub	eax, STREAM_SOCKET.rcv
750
 
751
	mov	[eax + SOCKET.lock], 0
752
	mov	ebx, eax	; if there is data, it must arrive in this new socket!
1514 hidnplayr 753
	jmp	.trim_then_step6
1159 hidnplayr 754
 
1254 hidnplayr 755
 
1529 hidnplayr 756
;------------
757
; Active Open
1159 hidnplayr 758
 
1514 hidnplayr 759
align 4
760
.SYN_SENT:
1281 hidnplayr 761
 
1514 hidnplayr 762
	DEBUGF	1,"TCP state: syn_sent\n"
1159 hidnplayr 763
 
1514 hidnplayr 764
	test	[edx + TCP_segment.Flags], TH_ACK
765
	jz	@f
1281 hidnplayr 766
 
1514 hidnplayr 767
	mov	eax, [edx + TCP_segment.AckNumber]
768
	cmp	eax, [ebx + TCP_SOCKET.ISS]
769
	jle	.drop_with_reset
1281 hidnplayr 770
 
1529 hidnplayr 771
;        mov     eax, [edx + TCP_segment.AckNumber]
1533 hidnplayr 772
	cmp	eax, [ebx + TCP_SOCKET.SND_MAX]
773
	jg	.drop_with_reset
1514 hidnplayr 774
       @@:
1281 hidnplayr 775
 
1514 hidnplayr 776
	test	[edx + TCP_segment.Flags], TH_RST
777
	jz	@f
1281 hidnplayr 778
 
1514 hidnplayr 779
	test	[edx + TCP_segment.Flags], TH_ACK
780
	jz	.drop
1281 hidnplayr 781
 
1716 hidnplayr 782
	mov	ebx, ECONNREFUSED
783
	call	TCP_drop
1159 hidnplayr 784
 
1514 hidnplayr 785
	jmp	.drop
786
       @@:
1159 hidnplayr 787
 
1514 hidnplayr 788
	test	[edx + TCP_segment.Flags], TH_SYN
789
	jz	.drop
1318 hidnplayr 790
 
1529 hidnplayr 791
; at this point, segment seems to be valid
792
 
1514 hidnplayr 793
	test	[edx + TCP_segment.Flags], TH_ACK
1529 hidnplayr 794
	jz	.no_syn_ack
1514 hidnplayr 795
 
1529 hidnplayr 796
; now, process received SYN in response to an active open
797
 
1514 hidnplayr 798
	mov	eax, [edx + TCP_segment.AckNumber]
799
	mov	[ebx + TCP_SOCKET.SND_UNA], eax
800
	cmp	eax, [ebx + TCP_SOCKET.SND_NXT]
801
	jle	@f
802
	mov	[ebx + TCP_SOCKET.SND_NXT], eax
1529 hidnplayr 803
       @@:
1514 hidnplayr 804
 
1529 hidnplayr 805
  .no_syn_ack:
1514 hidnplayr 806
 
1529 hidnplayr 807
	mov	[ebx + TCP_SOCKET.timer_retransmission], 0	; disable retransmission
1514 hidnplayr 808
 
1529 hidnplayr 809
	push	[edx + TCP_segment.SequenceNumber]
810
	pop	[ebx + TCP_SOCKET.IRS]
811
 
1533 hidnplayr 812
	TCP_rcvseqinit ebx
1529 hidnplayr 813
 
814
	mov	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
815
 
816
	mov	eax, [ebx + TCP_SOCKET.SND_UNA]
817
	cmp	eax, [ebx + TCP_SOCKET.ISS]
818
	jle	.simultaneous_open
819
 
820
	test	[edx + TCP_segment.Flags], TH_ACK
821
	jz	.simultaneous_open
822
 
823
	DEBUGF	1,"TCP: active open\n"
824
 
825
; TODO: update stats
1533 hidnplayr 826
; TODO: set general socket state to connected
1514 hidnplayr 827
 
828
	mov	[ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
829
 
830
; TODO: check if we should scale the connection (567-572)
831
; TODO: update RTT estimators
832
 
1529 hidnplayr 833
	jmp	.trimthenstep6
1514 hidnplayr 834
 
1529 hidnplayr 835
  .simultaneous_open:
1514 hidnplayr 836
 
1529 hidnplayr 837
	DEBUGF	1,"TCP: simultaneous open\n"
1514 hidnplayr 838
; We have received a syn but no ACK, so we are having a simultaneous open..
839
	mov	[ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
840
 
841
;-------------------------------------
842
; Common processing for receipt of SYN
843
 
844
  .trimthenstep6:
845
 
846
	inc	[edx + TCP_segment.SequenceNumber]
847
 
848
	cmp	cx, [ebx + TCP_SOCKET.RCV_WND]
849
	jle	@f
850
 
851
	movzx	eax, cx
852
	sub	ax, [ebx + TCP_SOCKET.RCV_WND]
853
	; TODO: 592
854
	mov	cx, [ebx + TCP_SOCKET.RCV_WND]
855
	; TODO...
856
       @@:
857
	;;;;;
1529 hidnplayr 858
	jmp	.step6
1514 hidnplayr 859
 
860
 
1529 hidnplayr 861
  .trim_then_step6:
1159 hidnplayr 862
 
1514 hidnplayr 863
;----------------------------
864
; trim any data not in window
1159 hidnplayr 865
 
1533 hidnplayr 866
	DEBUGF	1,"Trimming window\n"
867
 
1514 hidnplayr 868
	mov	eax, [ebx + TCP_SOCKET.RCV_NXT]
869
	sub	eax, [edx + TCP_segment.SequenceNumber]
1318 hidnplayr 870
 
1514 hidnplayr 871
	test	eax, eax
1533 hidnplayr 872
	jz	.no_duplicate
1274 hidnplayr 873
 
1514 hidnplayr 874
	test	[edx + TCP_segment.Flags], TH_SYN
875
	jz	.no_drop
876
 
877
	and	[edx + TCP_segment.Flags], not (TH_SYN)
878
	inc	[edx + TCP_segment.SequenceNumber]
879
 
880
	cmp	[edx + TCP_segment.UrgentPointer], 1
881
	jl	@f
882
 
883
	dec	[edx + TCP_segment.UrgentPointer]
884
 
885
	jmp	.no_drop
886
       @@:
887
 
888
	and	[edx + TCP_segment.Flags], not (TH_URG)
889
	dec	eax
1533 hidnplayr 890
	jz	.no_duplicate
1514 hidnplayr 891
  .no_drop:
892
 
1533 hidnplayr 893
	DEBUGF	1,"Going to drop %u out of %u bytes\n", eax, ecx
1529 hidnplayr 894
 
1514 hidnplayr 895
; eax holds number of bytes to drop
896
 
897
;----------------------------------
898
; Check for entire duplicate packet
899
 
900
	cmp	eax, ecx
901
	jge	.duplicate
902
 
903
	;;; TODO: figure 28.30
904
 
905
;------------------------
906
; Check for duplicate FIN
907
 
908
	test	[edx + TCP_segment.Flags], TH_FIN
909
	jz	@f
910
	inc	ecx
911
	cmp	eax, ecx
912
	dec	ecx
913
	jne	@f
914
 
915
	mov	eax, ecx
916
	and	[edx + TCP_segment.Flags], not TH_FIN
1529 hidnplayr 917
	or	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1514 hidnplayr 918
	jmp	.no_duplicate
919
       @@:
920
 
921
	; Handle the case when a bound socket connects to itself
922
	; Allow packets with a SYN and an ACKto continue with the processing
923
 
924
;-------------------------------------
925
; Generate duplicate ACK if nescessary
926
 
927
; This code also handles simultaneous half-open or self-connects
928
 
929
	test	eax, eax
930
	jnz	.drop_after_ack
931
 
932
	cmp	[edx + TCP_segment.Flags], TH_ACK
933
	jz	.drop_after_ack
934
 
935
  .duplicate:
936
 
1533 hidnplayr 937
	DEBUGF	1,"Duplicate received\n"
1529 hidnplayr 938
 
1514 hidnplayr 939
;----------------------------------------
940
; Update statistics for duplicate packets
941
 
942
	;;; TODO
943
 
1529 hidnplayr 944
	jmp	.drop	       ;;; DROP the packet ??
1514 hidnplayr 945
 
946
  .no_duplicate:
947
 
948
;-----------------------------------------------
949
; Remove duplicate data and update urgent offset
950
 
951
	add	[edx + TCP_segment.SequenceNumber], eax
952
 
953
	;;; TODO
954
 
955
	sub	[edx + TCP_segment.UrgentPointer], ax
956
	jg	@f
957
 
958
	and	[edx + TCP_segment.Flags], not (TH_URG)
959
	mov	[edx + TCP_segment.UrgentPointer], 0
960
       @@:
961
 
962
;--------------------------------------------------
963
; Handle data that arrives after process terminates
964
 
965
	cmp	[ebx + SOCKET.PID], 0
1533 hidnplayr 966
	jg	@f
1514 hidnplayr 967
 
968
	cmp	[ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT
969
	jle	@f
970
 
971
	test	ecx, ecx
972
	jz	@f
973
 
974
	;;; Close the socket
975
	;;; update stats
976
 
977
	jmp	.drop_with_reset
978
       @@:
979
 
980
;----------------------------------------
981
; Remove data beyond right edge of window
982
 
983
	mov	eax, [edx + TCP_segment.SequenceNumber]
984
	add	eax, ecx
985
	sub	eax, [ebx + TCP_SOCKET.RCV_NXT]
986
	sub	ax, [ebx + TCP_SOCKET.RCV_WND]
987
 
988
	; eax now holds the number of bytes to drop
989
 
990
	jle	.no_excess_data
991
 
992
	;;; TODO: update stats
993
 
994
	cmp	eax, ecx
995
	jl	.dont_drop_all
996
 
997
;;; TODO 700-736
998
 
999
  .dont_drop_all:
1000
 
1001
  .no_excess_data:
1002
 
1003
;-----------------
1004
; Record timestamp
1005
 
1006
	;;; TODO 737-746
1007
 
1008
;------------------
1009
; Process RST flags
1010
 
1011
	test	[edx + TCP_segment.Flags], TH_RST
1012
	jz	.rst_skip
1013
 
1529 hidnplayr 1014
	DEBUGF	1,"Got an RST flag"
1015
 
1514 hidnplayr 1016
	mov	eax, [ebx + TCP_SOCKET.t_state]
1017
	shl	eax, 2
1018
	jmp	dword [eax + .rst_sw_list]
1019
 
1020
  .rst_sw_list:
1021
	dd	.rst_skip	;TCB_CLOSED
1022
	dd	.rst_skip	;TCB_LISTEN
1023
	dd	.rst_skip	;TCB_SYN_SENT
1024
	dd	.econnrefused	;TCB_SYN_RECEIVED
1025
	dd	.econnreset	;TCB_ESTABLISHED
1026
	dd	.econnreset	;TCB_CLOSE_WAIT
1027
	dd	.econnreset	;TCB_FIN_WAIT_1
1028
	dd	.rst_close	;TCB_CLOSING
1029
	dd	.rst_close	;TCB_LAST_ACK
1030
	dd	.econnreset	;TCB_FIN_WAIT_2
1031
	dd	.rst_close	;TCB_TIMED_WAIT
1032
 
1033
  .econnrefused:
1034
 
1529 hidnplayr 1035
	DEBUGF	1,"Connection refused"
1036
 
1514 hidnplayr 1037
	;;; TODO: debug info
1038
 
1039
	jmp	.close
1040
 
1041
  .econnreset:
1042
 
1529 hidnplayr 1043
	DEBUGF	1,"Connection reset"
1044
 
1514 hidnplayr 1045
	;;; TODO: debug info
1529 hidnplayr 1046
  .close:
1514 hidnplayr 1047
 
1529 hidnplayr 1048
	DEBUGF	1,"Closing connection"
1049
 
1514 hidnplayr 1050
	;;; update stats
1051
 
1052
  .rst_close:
1053
 
1534 hidnplayr 1054
	DEBUGF	1,"Closing with reset\n"
1529 hidnplayr 1055
 
1514 hidnplayr 1056
	;;; Close the socket
1057
	jmp	.drop
1058
 
1059
  .rst_skip:
1060
 
1061
;--------------------------------------
1062
; handle SYN-full and ACK-less segments
1063
 
1064
	test	[edx + TCP_segment.Flags], TH_SYN
1065
	jz	@f
1066
 
1716 hidnplayr 1067
	mov	ebx, ECONNRESET
1068
	call	TCP_drop
1069
 
1514 hidnplayr 1070
	jmp	.drop_with_reset
1071
 
1072
	test	[edx + TCP_segment.Flags], TH_ACK
1073
	jz	.drop
1534 hidnplayr 1074
      @@:
1514 hidnplayr 1075
;----------------
1076
; Process the ACK
1077
 
1078
	cmp	[ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
1079
	jg	.ack_dup
1080
	jl	.ack_nodup
1081
 
1534 hidnplayr 1082
	DEBUGF	1,"TCP state = syn received\n"
1533 hidnplayr 1083
 
1514 hidnplayr 1084
	;;;;;
1085
 
1536 hidnplayr 1086
  .ack_nodup:
1514 hidnplayr 1087
 
1536 hidnplayr 1088
	DEBUGF	1,"New ACK\n"
1533 hidnplayr 1089
 
1514 hidnplayr 1090
 
1091
 
1536 hidnplayr 1092
  .ack_dup:
1514 hidnplayr 1093
 
1536 hidnplayr 1094
	;;;;
1533 hidnplayr 1095
 
1514 hidnplayr 1096
;-------------------------------------------------
1519 hidnplayr 1097
; If the congestion window was inflated to account
1514 hidnplayr 1098
; for the other side's cached packets, retrace it
1099
 
1100
	;;;; 888 -  902
1101
 
1102
 
1103
;------------------------------------------
1104
; RTT measurements and retransmission timer
1105
 
1106
	;;;;; 903 - 926
1107
 
1519 hidnplayr 1108
	mov	[ebx + TCP_SOCKET.timer_retransmission], 0
1514 hidnplayr 1109
 
1519 hidnplayr 1110
	mov	eax, [ebx + TCP_SOCKET.SND_MAX]
1111
	cmp	eax, [edx + TCP_segment.AckNumber]
1112
	je	.all_outstanding
1543 hidnplayr 1113
	mov	[ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value (use a macro for it)
1519 hidnplayr 1114
  .all_outstanding:
1115
 
1514 hidnplayr 1116
;-------------------------------------------
1117
; Open congestion window in response to ACKs
1118
 
1119
	;;;;
1120
 
1121
 
1122
;------------------------------------------
1123
; Remove acknowledged data from send buffer
1124
 
1536 hidnplayr 1125
	pusha
1126
; Delete acknowledged bytes from send buffer
1127
	mov	ecx, [edx + TCP_segment.AckNumber]
1128
	sub	ecx, [ebx + TCP_SOCKET.SND_UNA]
1533 hidnplayr 1129
	lea	eax, [ebx + STREAM_SOCKET.snd]
1536 hidnplayr 1130
	call	SOCKET_ring_free
1131
	popa
1514 hidnplayr 1132
 
1536 hidnplayr 1133
 
1134
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  code missing (943?)
1135
 
1542 hidnplayr 1136
 
1137
 
1536 hidnplayr 1138
	mov	eax, [edx + TCP_segment.AckNumber]
1139
	mov	[ebx + TCP_SOCKET.SND_UNA], eax
1140
 
1141
	cmp	eax, [ebx + TCP_SOCKET.SND_NXT]
1142
	jl	@f
1143
	mov	[ebx + TCP_SOCKET.SND_NXT], eax
1144
       @@:
1145
 
1146
 
1514 hidnplayr 1147
;---------------------------------------
1148
; Wake up process waiting on send buffer
1149
 
1529 hidnplayr 1150
	mov	eax, ebx
1151
	call	SOCKET_notify_owner
1514 hidnplayr 1152
 
1153
	mov	eax, [ebx + TCP_SOCKET.t_state]
1154
	shl	eax, 2
1155
	jmp	dword [eax + .ACK_sw_list]
1156
 
1157
  .ACK_sw_list:
1158
	dd	.step6		;TCB_CLOSED
1159
	dd	.step6		;TCB_LISTEN
1160
	dd	.step6		;TCB_SYN_SENT
1161
	dd	.step6		;TCB_SYN_RECEIVED
1162
	dd	.step6		;TCB_ESTABLISHED
1163
	dd	.step6		;TCB_CLOSE_WAIT
1164
	dd	._963		;TCB_FIN_WAIT_1
1165
	dd	._958		;TCB_CLOSING
1166
	dd	._999		;TCB_LAST_ACK
1167
	dd	.step6		;TCB_FIN_WAIT_2
1168
	dd	._1010		;TCB_TIMED_WAIT
1169
 
1170
 
1536 hidnplayr 1171
  ._963:
1514 hidnplayr 1172
 
1173
 
1174
	jmp	.step6
1175
 
1176
 
1536 hidnplayr 1177
  ._958:
1514 hidnplayr 1178
 
1179
	jmp	.step6
1180
 
1536 hidnplayr 1181
  ._999:
1514 hidnplayr 1182
 
1183
	jmp	.step6
1184
 
1185
 
1536 hidnplayr 1186
  ._1010:
1514 hidnplayr 1187
 
1188
	jmp	.step6
1189
 
1190
 
1536 hidnplayr 1191
  .step6:
1514 hidnplayr 1192
 
1193
	DEBUGF	1,"step 6\n"
1194
 
1536 hidnplayr 1195
;----------------------------------------------
1196
; check if we need to update window information
1514 hidnplayr 1197
 
1198
	test	[edx + TCP_segment.Flags], TH_ACK
1199
	jz	.no_window_update
1200
 
1201
	mov	eax, [ebx + TCP_SOCKET.SND_WL1]
1202
	cmp	eax, [edx + TCP_segment.SequenceNumber]
1536 hidnplayr 1203
	jl	.update_window
1204
	jg	@f
1514 hidnplayr 1205
 
1206
	mov	eax, [ebx + TCP_SOCKET.SND_WL2]
1207
	cmp	eax, [edx + TCP_segment.AckNumber]
1536 hidnplayr 1208
	jl	.update_window
1209
	jg	.no_window_update
1210
       @@:
1514 hidnplayr 1211
 
1543 hidnplayr 1212
	mov	eax, [ebx + TCP_SOCKET.SND_WL2]
1536 hidnplayr 1213
	cmp	eax, [edx + TCP_segment.AckNumber]
1214
	jne	.no_window_update
1215
 
1216
	movzx	eax, [edx + TCP_segment.Window]
1514 hidnplayr 1217
	cmp	eax, [ebx + TCP_SOCKET.SND_WND]
1536 hidnplayr 1218
	jle	.no_window_update
1514 hidnplayr 1219
 
1536 hidnplayr 1220
  .update_window:
1514 hidnplayr 1221
 
1536 hidnplayr 1222
	DEBUGF	1,"Updating window\n"
1514 hidnplayr 1223
 
1536 hidnplayr 1224
;----------------------------------
1225
; Keep track of pure window updates
1226
 
1227
;        test    ecx, ecx
1228
;        jz      @f
1229
;
1230
;        mov     eax, [ebx + TCP_SOCKET.SND_WL2]
1231
;        cmp     eax, [edx + TCP_segment.AckNumber]
1232
;        jne     @f
1233
;
1234
;        ;; mov eax, tiwin
1235
;        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
1236
;        jle     @f
1237
;
1238
;        ;;; update stats
1239
;
1240
;       @@:
1241
 
1543 hidnplayr 1242
	mov	eax, dword [edx + TCP_segment.Window]
1514 hidnplayr 1243
	cmp	eax, [ebx + TCP_SOCKET.max_sndwnd]
1244
	jle	@f
1245
	mov	[ebx + TCP_SOCKET.max_sndwnd], eax
1246
       @@:
1247
	mov	[ebx + TCP_SOCKET.SND_WND], eax
1248
 
1536 hidnplayr 1249
	push	[edx + TCP_segment.SequenceNumber]
1250
	pop	[ebx + TCP_SOCKET.SND_WL1]
1514 hidnplayr 1251
 
1536 hidnplayr 1252
	push	[edx + TCP_segment.AckNumber]
1253
	pop	[ebx + TCP_SOCKET.SND_WL2]
1514 hidnplayr 1254
 
1255
	;;; needoutput = 1
1256
 
1257
  .no_window_update:
1258
 
1259
;-----------------
1260
; process URG flag
1261
 
1262
	test	[edx + TCP_segment.Flags], TH_URG
1263
	jz	.not_urgent
1264
 
1265
	cmp	[edx + TCP_segment.UrgentPointer], 0
1266
	jz	.not_urgent
1267
 
1268
	cmp	[ebx + TCP_SOCKET.t_state], TCB_TIMED_WAIT
1269
	je	.not_urgent
1270
 
1271
; Ignore bogus urgent offsets
1272
 
1273
	;;; 1040-1050
1274
 
1275
	movzx	eax, [edx + TCP_segment.UrgentPointer]
1533 hidnplayr 1276
	add	eax, [ebx + STREAM_SOCKET.rcv + RING_BUFFER.size]
1514 hidnplayr 1277
	cmp	eax, SOCKET_MAXDATA
1278
	jle	.not_urgent
1279
 
1280
	mov	[edx + TCP_segment.UrgentPointer], 0
1281
	and	[edx + TCP_segment.Flags], not (TH_URG)
1282
	jmp	.do_data
1283
 
1284
  .not_urgent:
1285
 
1286
;--------------------------------------
1287
; processing of received urgent pointer
1288
 
1529 hidnplayr 1289
	;;; TODO (1051-1093)
1514 hidnplayr 1290
 
1529 hidnplayr 1291
;--------------------------------
1292
; process the data in the segment
1514 hidnplayr 1293
 
1529 hidnplayr 1294
  .do_data:
1514 hidnplayr 1295
 
1534 hidnplayr 1296
	DEBUGF	1,"TCP: do data (%u)\n", ecx
1514 hidnplayr 1297
 
1298
	test	[edx + TCP_segment.Flags], TH_FIN
1529 hidnplayr 1299
	jnz	.process_fin
1514 hidnplayr 1300
 
1533 hidnplayr 1301
	cmp	[ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1
1514 hidnplayr 1302
	jge	.dont_do_data
1303
 
1533 hidnplayr 1304
	test	ecx, ecx
1305
	jz	.final_processing
1306
 
1514 hidnplayr 1307
	DEBUGF	1,"Processing data in segment\n"
1308
 
1533 hidnplayr 1309
;; TODO: check if data is in sequence !
1514 hidnplayr 1310
 
1533 hidnplayr 1311
	movzx	eax, [edx + TCP_segment.DataOffset]		;;; todo: remember this in.. edi ?
1312
	and	eax, 0xf0
1313
	shr	al, 2
1314
 
1315
	lea	esi, [edx + eax]
1316
 
1317
	or	[ebx + TCP_SOCKET.t_flags], TF_DELACK
1543 hidnplayr 1318
	add	[ebx + TCP_SOCKET.RCV_NXT], ecx
1533 hidnplayr 1319
 
1320
	lea	eax, [ebx + STREAM_SOCKET.rcv]
1321
	call	SOCKET_ring_write
1322
 
1323
	mov	eax, ebx
1324
	call	SOCKET_notify_owner
1325
 
1514 hidnplayr 1326
	jmp	.final_processing
1327
 
1328
 
1329
  .dont_do_data:
1330
 
1331
;---------------
1332
; FIN processing
1333
 
1334
  .process_fin:
1335
 
1336
	DEBUGF	1,"Processing FIN\n"
1337
 
1338
	mov	eax, [ebx + TCP_SOCKET.t_state]
1339
	shl	eax, 2
1340
	jmp	dword [eax + .FIN_sw_list]
1341
 
1342
  .FIN_sw_list:
1343
	dd	.no_fin 	;TCB_CLOSED
1344
	dd	.no_fin 	;TCB_LISTEN
1345
	dd	.no_fin 	;TCB_SYN_SENT
1533 hidnplayr 1346
	dd	.fin_syn_est	;TCB_SYN_RECEIVED
1347
	dd	.fin_syn_est	;TCB_ESTABLISHED
1514 hidnplayr 1348
	dd	.no_fin 	;TCB_CLOSE_WAIT
1533 hidnplayr 1349
	dd	.fin_wait1	;TCB_FIN_WAIT_1
1514 hidnplayr 1350
	dd	.no_fin 	;TCB_CLOSING
1351
	dd	.no_fin 	;TCB_LAST_ACK
1533 hidnplayr 1352
	dd	.fin_wait2	;TCB_FIN_WAIT_2
1353
	dd	.fin_timed	;TCB_TIMED_WAIT
1514 hidnplayr 1354
 
1355
 
1356
 
1533 hidnplayr 1357
  .fin_syn_est:
1514 hidnplayr 1358
 
1533 hidnplayr 1359
	jmp	.final_processing
1514 hidnplayr 1360
 
1533 hidnplayr 1361
  .fin_wait1:
1514 hidnplayr 1362
 
1533 hidnplayr 1363
	jmp	.final_processing
1514 hidnplayr 1364
 
1533 hidnplayr 1365
  .fin_wait2:
1514 hidnplayr 1366
 
1533 hidnplayr 1367
	jmp	.final_processing
1368
 
1369
  .fin_timed:
1370
 
1371
	jmp	.final_processing
1372
 
1514 hidnplayr 1373
  .no_fin:
1374
 
1375
;-----------------
1376
; Final processing
1377
 
1378
  .final_processing:
1379
 
1380
	DEBUGF	1,"Final processing\n"
1381
 
1533 hidnplayr 1382
	mov	[ebx + SOCKET.lock], 0
1383
 
1514 hidnplayr 1384
	;;; if debug enabled, output packet
1385
 
1386
	;test    ;;;needoutput = 1
1387
	;jnz     .outputnow
1388
 
1389
	test	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1529 hidnplayr 1390
	jnz	.ack_now
1514 hidnplayr 1391
 
1529 hidnplayr 1392
	call	kernel_free
1393
	add	esp, 4
1394
	ret
1395
 
1396
  .ack_now:
1397
 
1398
	DEBUGF	1,"ACK now!\n"
1399
 
1400
	push	ebx
1401
	mov	eax, ebx
1514 hidnplayr 1402
	call	TCP_output
1529 hidnplayr 1403
	pop	ebx
1514 hidnplayr 1404
 
1274 hidnplayr 1405
	call	kernel_free
1529 hidnplayr 1406
	add	esp, 4
1407
	ret
1274 hidnplayr 1408
 
1514 hidnplayr 1409
;------------------------------------------
1410
; Generate an ACK, droping incoming segment
1274 hidnplayr 1411
 
1514 hidnplayr 1412
align 4
1413
.drop_after_ack:
1274 hidnplayr 1414
 
1514 hidnplayr 1415
	DEBUGF	1,"Drop after ACK\n"
1274 hidnplayr 1416
 
1514 hidnplayr 1417
	test	[edx + TCP_segment.Flags], TH_RST
1418
	jnz	.drop
1274 hidnplayr 1419
 
1514 hidnplayr 1420
	and	[ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1274 hidnplayr 1421
 
1529 hidnplayr 1422
	push	ebx
1423
	mov	eax, ebx
1514 hidnplayr 1424
	call	TCP_output
1529 hidnplayr 1425
	pop	ebx
1318 hidnplayr 1426
 
1514 hidnplayr 1427
	call	kernel_free
1529 hidnplayr 1428
	add	esp, 4
1429
	ret
1274 hidnplayr 1430
 
1514 hidnplayr 1431
 
1432
;-------------------------------------------
1433
; Generate an RST, dropping incoming segment
1434
 
1435
align 4
1436
.drop_with_reset:
1437
 
1438
	DEBUGF	1,"Drop with reset\n"
1439
 
1440
	test	[edx + TCP_segment.Flags], TH_RST
1441
	jnz	.drop
1442
 
1443
	;;; if its a multicast/broadcast, also drop
1444
 
1445
	test	[edx + TCP_segment.Flags], TH_ACK
1446
	jnz	.respond_ack
1447
 
1448
	test	[edx + TCP_segment.Flags], TH_SYN
1449
	jnz	.respond_syn
1450
 
1451
	call	kernel_free
1529 hidnplayr 1452
	add	esp, 4
1453
	ret
1514 hidnplayr 1454
 
1455
  .respond_ack:
1456
 
1533 hidnplayr 1457
	mov	dl, TH_RST
1514 hidnplayr 1458
 
1533 hidnplayr 1459
	push	ebx
1529 hidnplayr 1460
	call	TCP_respond_segment
1533 hidnplayr 1461
	pop	ebx
1514 hidnplayr 1462
 
1463
	jmp	.destroy_new_socket
1464
 
1465
 
1466
  .respond_syn:
1467
 
1533 hidnplayr 1468
	mov	dl, TH_RST + TH_ACK
1514 hidnplayr 1469
 
1533 hidnplayr 1470
	push	ebx
1471
	call	TCP_respond_socket
1472
	pop	ebx
1514 hidnplayr 1473
 
1474
	jmp	.destroy_new_socket
1475
 
1476
;-----
1477
; Drop
1478
 
1479
align 4
1480
.drop:
1481
 
1482
	DEBUGF	1,"Dropping packet\n"
1483
 
1484
	;;;; If debugging options are enabled, output the packet somwhere
1485
 
1486
  .destroy_new_socket:
1487
 
1488
	;;;; kill the newly created socket
1489
 
1490
	call	kernel_free
1529 hidnplayr 1491
	add	esp, 4
1492
	ret
1514 hidnplayr 1493
 
1494
 
1495
 
1496
 
1497
 
1498
 
1499
;---------------------------
1500
;
1501
; TCP_pull_out_of_band
1502
;
1503
; IN:  eax =
1504
;      ebx = socket ptr
1505
;      edx = tcp packet ptr
1506
;
1507
; OUT: /
1508
;
1509
;---------------------------
1510
 
1511
align 4
1512
TCP_pull_out_of_band:
1513
 
1514
	DEBUGF	1,"TCP_pull_out_of_band\n"
1515
 
1516
	;;;; 1282-1305
1517
 
1318 hidnplayr 1518
	ret
1519
 
1520
 
1521
 
1522
;-----------------------------------------------------------------
1523
;
1514 hidnplayr 1524
; TCP_output
1318 hidnplayr 1525
;
1519 hidnplayr 1526
; IN:  eax = socket pointer
1514 hidnplayr 1527
;
1318 hidnplayr 1528
; OUT: /
1529
;
1530
;-----------------------------------------------------------------
1531
align 4
1514 hidnplayr 1532
TCP_output:
1318 hidnplayr 1533
 
1514 hidnplayr 1534
	DEBUGF 1,"TCP_output, socket: %x\n", eax
1318 hidnplayr 1535
 
1514 hidnplayr 1536
; We'll detect the length of the data to be transmitted, and flags to be used
1537
; If there is some data, or any critical controls to send (SYN / RST), then transmit
1538
; Otherwise, investigate further
1318 hidnplayr 1539
 
1514 hidnplayr 1540
	mov	ebx, [eax + TCP_SOCKET.SND_MAX]
1541
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1542
	jne	.not_idle
1318 hidnplayr 1543
 
1514 hidnplayr 1544
	mov	ebx, [eax + TCP_SOCKET.t_idle]
1545
	cmp	ebx, [eax + TCP_SOCKET.t_rxtcur]
1546
	jle	.not_idle
1318 hidnplayr 1547
 
1514 hidnplayr 1548
; We have been idle for a while and no ACKS are expected to clock out any data we send..
1549
; Slow start to get ack "clock" running again.
1318 hidnplayr 1550
 
1514 hidnplayr 1551
	mov	ebx, [eax + TCP_SOCKET.t_maxseg]
1552
	mov	[eax + TCP_SOCKET.SND_CWND], ebx
1318 hidnplayr 1553
 
1514 hidnplayr 1554
  .not_idle:
1555
  .again:
1556
	mov	ebx, [eax + TCP_SOCKET.SND_NXT] 	; calculate offset
1557
	sub	ebx, [eax + TCP_SOCKET.SND_UNA] 	;
1318 hidnplayr 1558
 
1514 hidnplayr 1559
	mov	ecx, [eax + TCP_SOCKET.SND_WND] 	; determine window
1560
	cmp	ecx, [eax + TCP_SOCKET.SND_CWND]	;
1561
	jl	@f					;
1562
	mov	ecx, [eax + TCP_SOCKET.SND_CWND]	;
1563
       @@:						;
1318 hidnplayr 1564
 
1529 hidnplayr 1565
	call	TCP_outflags	; in dl
1318 hidnplayr 1566
 
1514 hidnplayr 1567
; If in persist timeout with window of 0, send 1 byte.
1568
; Otherwise, if window is small but nonzero, and timer expired,
1569
; we will send what we can and go to transmit state
1318 hidnplayr 1570
 
1514 hidnplayr 1571
	test	[eax + TCP_SOCKET.t_force], -1
1572
	jz	.no_persist_timeout
1318 hidnplayr 1573
 
1514 hidnplayr 1574
	test	ecx, ecx
1575
	jnz	.no_zero_window
1255 hidnplayr 1576
 
1533 hidnplayr 1577
	cmp	ebx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1578
	jge	@f
1255 hidnplayr 1579
 
1514 hidnplayr 1580
	and	dl, not (TH_FIN)	  ; clear the FIN flag    ??? how can it be set before?
1255 hidnplayr 1581
 
1514 hidnplayr 1582
       @@:
1583
	inc	ecx
1584
	jmp	.no_persist_timeout
1255 hidnplayr 1585
 
1514 hidnplayr 1586
  .no_zero_window:
1254 hidnplayr 1587
 
1543 hidnplayr 1588
	mov	[eax + TCP_SOCKET.timer_persist], 0
1514 hidnplayr 1589
	mov	[eax + TCP_SOCKET.t_rxtshift], 0
1254 hidnplayr 1590
 
1514 hidnplayr 1591
  .no_persist_timeout:
1159 hidnplayr 1592
 
1514 hidnplayr 1593
;;;106
1159 hidnplayr 1594
 
1533 hidnplayr 1595
	mov	esi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1596
	cmp	esi, ecx
1597
	jl	@f
1598
	mov	esi, ecx
1599
       @@:
1600
	sub	esi, ebx
1254 hidnplayr 1601
 
1514 hidnplayr 1602
	cmp	esi, -1
1603
	jne	.not_minus_one
1159 hidnplayr 1604
 
1514 hidnplayr 1605
; If FIN has been set, but not ACKed, and we havent been called to retransmit,
1606
; len (esi) will be -1
1607
; Otherwise, window shrank after we sent into it.
1608
; If window shrank to 0, cancel pending retransmit and pull SND_NXT back to (closed) window
1609
; We will enter persist state below.
1610
; If window didn't close completely, just wait for an ACK
1159 hidnplayr 1611
 
1514 hidnplayr 1612
	xor	esi, esi
1159 hidnplayr 1613
 
1514 hidnplayr 1614
	test	ecx, ecx
1615
	jnz	@f
1159 hidnplayr 1616
 
1529 hidnplayr 1617
	mov	[eax + TCP_SOCKET.timer_retransmission], 0   ; cancel retransmit
1274 hidnplayr 1618
 
1514 hidnplayr 1619
	push	[eax + TCP_SOCKET.SND_UNA]
1620
	pop	[eax + TCP_SOCKET.SND_NXT]
1621
       @@:
1254 hidnplayr 1622
 
1514 hidnplayr 1623
  .not_minus_one:
1254 hidnplayr 1624
 
1514 hidnplayr 1625
;;; 124
1159 hidnplayr 1626
 
1514 hidnplayr 1627
	cmp	esi, [eax + TCP_SOCKET.t_maxseg]
1628
	jle	@f
1274 hidnplayr 1629
 
1514 hidnplayr 1630
	mov	esi, [eax + TCP_SOCKET.t_maxseg]
1631
	;sendalot = 1
1274 hidnplayr 1632
 
1514 hidnplayr 1633
       @@:
1274 hidnplayr 1634
 
1514 hidnplayr 1635
;;; 128
1274 hidnplayr 1636
 
1514 hidnplayr 1637
	mov	edi, [eax + TCP_SOCKET.SND_NXT]
1638
	add	edi, esi	; len
1639
	sub	edi, [eax + TCP_SOCKET.SND_UNA]
1533 hidnplayr 1640
	add	edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1514 hidnplayr 1641
	cmp	edi, 0
1642
	jle	@f
1274 hidnplayr 1643
 
1514 hidnplayr 1644
	and	dl, not (TH_FIN)	  ; clear the FIN flag
1159 hidnplayr 1645
 
1514 hidnplayr 1646
       @@:
1159 hidnplayr 1647
 
1648
 
1529 hidnplayr 1649
; set ecx to space available in receive buffer
1650
; From now on, ecx will be the window we advertise to the other end
1159 hidnplayr 1651
 
1529 hidnplayr 1652
	mov	ecx, SOCKET_MAXDATA
1533 hidnplayr 1653
	sub	ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
1159 hidnplayr 1654
 
1514 hidnplayr 1655
;------------------------------
1656
; Sender silly window avoidance
1159 hidnplayr 1657
 
1529 hidnplayr 1658
	cmp	ecx, [eax + TCP_SOCKET.t_maxseg]
1514 hidnplayr 1659
	je	.send
1274 hidnplayr 1660
 
1514 hidnplayr 1661
;;; TODO: 144-145
1274 hidnplayr 1662
 
1514 hidnplayr 1663
	test	[eax + TCP_SOCKET.t_force], -1
1664
	jnz	.send
1274 hidnplayr 1665
 
1529 hidnplayr 1666
	mov	ebx, [eax + TCP_SOCKET.max_sndwnd]
1667
	shr	ebx, 1
1668
	cmp	ecx, ebx
1669
	jge	.send
1274 hidnplayr 1670
 
1529 hidnplayr 1671
	mov	ebx, [eax + TCP_SOCKET.SND_NXT]
1672
	cmp	ebx, [eax + TCP_SOCKET.SND_MAX]
1673
	jl	.send
1254 hidnplayr 1674
 
1514 hidnplayr 1675
;----------------------------------------
1676
; Check if a window update should be sent
1159 hidnplayr 1677
 
1529 hidnplayr 1678
	test	ecx, ecx	; window
1679
	jz	.no_window
1159 hidnplayr 1680
 
1514 hidnplayr 1681
;;; TODO 154-172
1159 hidnplayr 1682
 
1514 hidnplayr 1683
  .no_window:
1159 hidnplayr 1684
 
1514 hidnplayr 1685
;--------------------------
1686
; Should a segment be sent?
1159 hidnplayr 1687
 
1534 hidnplayr 1688
	test	[eax + TCP_SOCKET.t_flags], TF_ACKNOW
1514 hidnplayr 1689
	jnz	.send
1159 hidnplayr 1690
 
1514 hidnplayr 1691
	test	dl, TH_SYN + TH_RST
1692
	jnz	.send
1159 hidnplayr 1693
 
1534 hidnplayr 1694
	mov	ebx, [eax + TCP_SOCKET.SND_UP]
1695
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1514 hidnplayr 1696
	jg	.send
1249 hidnplayr 1697
 
1514 hidnplayr 1698
	test	dl, TH_FIN
1699
	jz	.enter_persist
1318 hidnplayr 1700
 
1534 hidnplayr 1701
	test	[eax + TCP_SOCKET.t_flags], TF_SENTFIN
1514 hidnplayr 1702
	jnz	.send
1254 hidnplayr 1703
 
1534 hidnplayr 1704
	mov	ebx, [eax + TCP_SOCKET.SND_NXT]
1705
	cmp	ebx, [eax + TCP_SOCKET.SND_UNA]
1514 hidnplayr 1706
	je	.send
1254 hidnplayr 1707
 
1514 hidnplayr 1708
;--------------------
1709
; Enter persist state
1318 hidnplayr 1710
 
1514 hidnplayr 1711
  .enter_persist:
1318 hidnplayr 1712
 
1519 hidnplayr 1713
	DEBUGF	1,"Entering persist state\n"
1318 hidnplayr 1714
 
1514 hidnplayr 1715
;--------------------------------------
1716
; No reason to send a segment, just ret
1318 hidnplayr 1717
 
1514 hidnplayr 1718
	DEBUGF	1,"No reason to send a segment\n"
1318 hidnplayr 1719
 
1514 hidnplayr 1720
	ret
1318 hidnplayr 1721
 
1722
 
1514 hidnplayr 1723
;-----------------------------------------------
1724
;
1725
; Send a segment
1726
;
1529 hidnplayr 1727
; eax = socket pointer
1514 hidnplayr 1728
;  dl = flags
1729
;
1730
;-----------------------------------------------
1318 hidnplayr 1731
 
1529 hidnplayr 1732
  .send:
1318 hidnplayr 1733
 
1514 hidnplayr 1734
	DEBUGF	1,"Preparing to send a segment\n"
1318 hidnplayr 1735
 
1529 hidnplayr 1736
	mov	edi, TCP_segment.Data	; edi will contain headersize
1318 hidnplayr 1737
 
1529 hidnplayr 1738
	sub	esp, 8			; create some space on stack
1739
	push	eax			; save this too..
1740
 
1514 hidnplayr 1741
;------------------------------------
1742
; Send options with first SYN segment
1318 hidnplayr 1743
 
1514 hidnplayr 1744
	test	dl, TH_SYN
1745
	jz	.no_options
1318 hidnplayr 1746
 
1529 hidnplayr 1747
	push	[eax + TCP_SOCKET.ISS]
1748
	pop	[eax + TCP_SOCKET.SND_NXT]
1318 hidnplayr 1749
 
1529 hidnplayr 1750
	test	[eax + TCP_SOCKET.t_flags], TF_NOOPT
1514 hidnplayr 1751
	jnz	.no_options
1318 hidnplayr 1752
 
1529 hidnplayr 1753
	mov	ecx, 1460
1754
	or	ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
1755
	bswap	ecx
1756
	push	ecx
1757
	add	di, 4
1514 hidnplayr 1758
 
1529 hidnplayr 1759
	test	[eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
1514 hidnplayr 1760
	jz	.no_syn
1761
 
1762
	test	dl, TH_ACK
1763
	jnz	.scale_opt
1764
 
1529 hidnplayr 1765
	test	[eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
1514 hidnplayr 1766
	jz	.no_syn
1767
 
1768
  .scale_opt:
1529 hidnplayr 1769
	movzx	ecx, byte [eax + TCP_SOCKET.request_r_scale]
1770
	or	ecx, TCP_OPT_WINDOW shl 24 + 4 shl 16 + TCP_OPT_NOP shl 8
1771
	bswap	ecx
1772
	pushd	ecx
1514 hidnplayr 1773
	add	di, 4
1159 hidnplayr 1774
 
1514 hidnplayr 1775
  .no_syn:
1159 hidnplayr 1776
 
1514 hidnplayr 1777
;------------------------------------
1778
; Make the timestamp option if needed
1159 hidnplayr 1779
 
1529 hidnplayr 1780
	test	[eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
1514 hidnplayr 1781
	jz	.no_timestamp
1159 hidnplayr 1782
 
1514 hidnplayr 1783
	test	dl, TH_RST
1784
	jnz	.no_timestamp
1785
 
1786
	test	dl, TH_ACK
1787
	jz	.timestamp
1788
 
1529 hidnplayr 1789
	test	[eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
1514 hidnplayr 1790
	jz	.no_timestamp
1791
 
1792
  .timestamp:
1529 hidnplayr 1793
	mov	esi, [timer_ticks]
1794
	bswap	esi
1795
	push	esi
1514 hidnplayr 1796
	pushw	0
1529 hidnplayr 1797
	pushd	TCP_OPT_TIMESTAMP + 10 shl 8 + TCP_OPT_NOP shl 16 + TCP_OPT_NOP shl 24
1514 hidnplayr 1798
	add	di, 10
1799
 
1800
  .no_timestamp:
1801
	;; TODO: check if we dont exceed the max segment size
1802
 
1803
  .no_options:
1529 hidnplayr 1804
	; eax = socket ptr
1805
	; edx = flags
1806
	; ecx = data size
1807
	; edi = header size
1808
	; esi = snd ring buff ptr
1514 hidnplayr 1809
 
1533 hidnplayr 1810
	mov	ecx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
1811
	cmp	ecx, [eax + TCP_SOCKET.t_maxseg]			;;; right?
1812
	jle	@f
1813
	mov	ecx, [eax + TCP_SOCKET.t_maxseg]
1814
       @@:
1514 hidnplayr 1815
	add	ecx, edi	; total TCP segment size
1816
 
1529 hidnplayr 1817
; Start by pushing all TCP header values in reverse order on stack
1818
; (essentially, creating the tcp header!)
1514 hidnplayr 1819
 
1529 hidnplayr 1820
	pushw	0	;        .UrgentPointer          dw ?
1821
	pushw	0	;        .Checksum               dw ?
1822
	pushw	0x00a0	;        .Window                 dw ?    ;;;;;;;
1823
	shl	edi, 2	;        .DataOffset             db ?  only 4 left-most bits
1824
	shl	dx, 8
1825
	or	dx, di	;        .Flags                  db ?
1826
	pushw	dx
1827
	shr	edi, 2	;        .DataOffset             db ? ;;;;
1514 hidnplayr 1828
 
1529 hidnplayr 1829
	push	[eax + TCP_SOCKET.RCV_NXT]	;        .AckNumber              dd ?
1543 hidnplayr 1830
	ntohd	[esp]
1159 hidnplayr 1831
 
1529 hidnplayr 1832
	push	[eax + TCP_SOCKET.SND_NXT]	;        .SequenceNumber         dd ?
1543 hidnplayr 1833
	ntohd	[esp]
1159 hidnplayr 1834
 
1529 hidnplayr 1835
	push	[eax + TCP_SOCKET.RemotePort]	;        .DestinationPort        dw ?
1543 hidnplayr 1836
	ntohw	[esp]
1249 hidnplayr 1837
 
1529 hidnplayr 1838
	push	[eax + TCP_SOCKET.LocalPort]	;        .SourcePort             dw ?
1543 hidnplayr 1839
	ntohw	[esp]
1274 hidnplayr 1840
 
1533 hidnplayr 1841
	push	edi		; header size
1274 hidnplayr 1842
 
1529 hidnplayr 1843
; Create the IP packet
1844
	mov	ebx, [eax + IP_SOCKET.LocalIP]	; source ip
1845
	mov	eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
1846
	mov	di, IP_PROTO_TCP shl 8 + 128
1847
	call	IPv4_output
1848
	jz	.fail
1274 hidnplayr 1849
 
1529 hidnplayr 1850
;-----------------------------------------
1851
; Move TCP header from stack to TCP packet
1274 hidnplayr 1852
 
1533 hidnplayr 1853
	push	ecx
1854
	mov	ecx, [esp+4]
1855
	lea	esi, [esp+4+4]
1529 hidnplayr 1856
	shr	ecx, 2
1857
	rep	movsd
1533 hidnplayr 1858
	pop	ecx		; full TCP packet size
1274 hidnplayr 1859
 
1533 hidnplayr 1860
	pop	esi		; headersize
1861
	add	esp, esi
1254 hidnplayr 1862
 
1533 hidnplayr 1863
	mov	[esp + 4], eax		; packet ptr
1530 hidnplayr 1864
	mov	[esp + 4+4], edx	; packet size
1254 hidnplayr 1865
 
1533 hidnplayr 1866
	mov	edx, edi		; begin of data
1867
	sub	edx, esi		; begin of packet (edi = begin of data)
1868
	push	ecx
1869
	sub	ecx, esi		; data size
1159 hidnplayr 1870
 
1514 hidnplayr 1871
;--------------
1872
; Copy the data
1159 hidnplayr 1873
 
1529 hidnplayr 1874
; eax = ptr to ring struct
1875
; ecx = buffer size
1876
; edi = ptr to buffer
1249 hidnplayr 1877
 
1536 hidnplayr 1878
;        test    ecx, ecx
1533 hidnplayr 1879
	mov	eax, [esp+4]		  ; socket ptr
1536 hidnplayr 1880
	add	[eax + TCP_SOCKET.SND_NXT], ecx
1881
	add	eax, STREAM_SOCKET.snd
1533 hidnplayr 1882
	push	edx
1529 hidnplayr 1883
	call	SOCKET_ring_read
1536 hidnplayr 1884
	pop	esi
1885
	pop	ecx
1529 hidnplayr 1886
	pop	eax
1254 hidnplayr 1887
 
1533 hidnplayr 1888
	test	[esi + TCP_segment.Flags], TH_SYN + TH_FIN
1889
	jz	@f
1890
	inc	[eax + TCP_SOCKET.SND_NXT]
1891
	;;; TODO: update sentfin flag
1892
       @@:
1254 hidnplayr 1893
 
1533 hidnplayr 1894
	mov	edx, [eax + TCP_SOCKET.SND_NXT]
1895
	cmp	edx, [eax + TCP_SOCKET.SND_MAX]
1896
	jle	@f
1897
	mov	[eax + TCP_SOCKET.SND_MAX], edx
1898
 
1899
	;;;; TODO: time transmission (420)
1900
       @@:
1901
 
1902
	;;; TODO: set retransmission timer
1903
 
1904
;--------------------
1905
; Create the checksum
1906
 
1529 hidnplayr 1907
	DEBUGF	1,"checksum: ptr=%x size=%u\n", esi, ecx
1159 hidnplayr 1908
 
1529 hidnplayr 1909
	TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
1910
	mov	[esi+TCP_segment.Checksum], dx
1911
 
1514 hidnplayr 1912
;----------------
1913
; Send the packet
1159 hidnplayr 1914
 
1529 hidnplayr 1915
	DEBUGF	1,"Sending TCP Packet to device %x\n", ebx
1916
	call	[ebx + NET_DEVICE.transmit]
1917
	ret
1159 hidnplayr 1918
 
1514 hidnplayr 1919
 
1529 hidnplayr 1920
  .fail:
1921
	pop	ecx
1922
	add	esp, ecx
1536 hidnplayr 1923
	add	esp, 4+8
1529 hidnplayr 1924
	DEBUGF 1,"TCP_output: failed\n"
1159 hidnplayr 1925
	ret
1926
 
1529 hidnplayr 1927
 
1928
 
1514 hidnplayr 1929
;-------------------------
1930
;
1931
; TCP_outflags
1932
;
1933
;  IN:  eax = socket ptr
1934
;
1935
;  OUT: edx = flags
1936
;
1937
;-------------------------
1249 hidnplayr 1938
align 4
1514 hidnplayr 1939
TCP_outflags:
1254 hidnplayr 1940
 
1514 hidnplayr 1941
	mov	edx, [eax + TCP_SOCKET.t_state]
1942
	movzx	edx, byte [edx + .flaglist]
1254 hidnplayr 1943
 
1514 hidnplayr 1944
	DEBUGF	1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
1945
 
1159 hidnplayr 1946
	ret
1947
 
1514 hidnplayr 1948
  .flaglist:
1159 hidnplayr 1949
 
1514 hidnplayr 1950
	db	TH_RST + TH_ACK 	; TCB_CLOSED
1951
	db	0			; TCB_LISTEN
1952
	db	TH_SYN			; TCB_SYN_SENT
1953
	db	TH_SYN + TH_ACK 	; TCB_SYN_RECEIVED
1954
	db		 TH_ACK 	; TCB_ESTABLISHED
1955
	db		 TH_ACK 	; TCB_CLOSE_WAIT
1956
	db	TH_SYN + TH_ACK 	; TCB_FIN_WAIT_1
1957
	db	TH_SYN + TH_ACK 	; TCB_CLOSING
1958
	db	TH_SYN + TH_ACK 	; TCB_LAST_ACK
1959
	db		 TH_ACK 	; TCB_FIN_WAIT_2
1960
	db		 TH_ACK 	; TCB_TIMED_WAIT
1249 hidnplayr 1961
 
1514 hidnplayr 1962
 
1529 hidnplayr 1963
 
1964
 
1514 hidnplayr 1965
;-------------------------
1966
;
1967
; TCP_drop
1968
;
1969
;  IN:  eax = socket ptr
1716 hidnplayr 1970
;       ebx = error number
1514 hidnplayr 1971
;
1716 hidnplayr 1972
;  OUT: eax = socket ptr
1514 hidnplayr 1973
;
1974
;-------------------------
1249 hidnplayr 1975
align 4
1514 hidnplayr 1976
TCP_drop:
1254 hidnplayr 1977
 
1514 hidnplayr 1978
	DEBUGF	1,"TCP_drop\n"
1254 hidnplayr 1979
 
1716 hidnplayr 1980
	cmp	[eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
1981
	jl	.no_syn_received
1159 hidnplayr 1982
 
1514 hidnplayr 1983
	mov	[eax + TCP_SOCKET.t_state], TCB_CLOSED
1159 hidnplayr 1984
 
1514 hidnplayr 1985
	call	TCP_output
1254 hidnplayr 1986
 
1716 hidnplayr 1987
;;; TODO: update stats
1514 hidnplayr 1988
 
1716 hidnplayr 1989
	jmp	TCP_close
1990
 
1991
  .no_syn_received:
1992
 
1993
;;; TODO: update stats
1994
 
1995
;;; TODO: check if error code is "Connection timed out' and handle accordingly
1996
 
1997
	mov	[eax + SOCKET.errorcode], ebx
1998
 
1999
	jmp	TCP_close
2000
 
2001
 
2002
;-------------------------
2003
;
2004
; TCP_close
2005
;
2006
;  IN:  eax = socket ptr
2007
;  OUT: eax = socket ptr
2008
;
2009
;-------------------------
2010
align 4
2011
TCP_close:
2012
 
2013
;;; TODO: update RTT and mean deviation
2014
;;; TODO: update slow start threshold
2015
;;; TODO: release connection resources
2016
 
1159 hidnplayr 2017
	ret
2018
 
2019
 
1254 hidnplayr 2020
 
2021
 
1514 hidnplayr 2022
;---------------------------------------
2023
;
1519 hidnplayr 2024
; The easy way to send an ACK/RST/keepalive segment
1514 hidnplayr 2025
;
1529 hidnplayr 2026
; TCP_respond_socket:
2027
;
2028
;  IN:  ebx = socket ptr
1519 hidnplayr 2029
;        cl = flags
1514 hidnplayr 2030
;
1529 hidnplayr 2031
;--------------------------------------
1514 hidnplayr 2032
align 4
1529 hidnplayr 2033
TCP_respond_socket:
1254 hidnplayr 2034
 
1529 hidnplayr 2035
	DEBUGF	1,"TCP_respond_socket\n"
1159 hidnplayr 2036
 
1519 hidnplayr 2037
;---------------------
2038
; Create the IP packet
2039
 
1529 hidnplayr 2040
	push	cx ebx
2041
	mov	eax, [ebx + IP_SOCKET.RemoteIP]
2042
	mov	ebx, [ebx + IP_SOCKET.LocalIP]
1519 hidnplayr 2043
	mov	ecx, TCP_segment.Data
1529 hidnplayr 2044
	mov	di , IP_PROTO_TCP shl 8 + 128
2045
	call	IPv4_output
1519 hidnplayr 2046
	test	edi, edi
2047
	jz	.error
1529 hidnplayr 2048
	pop	esi cx
2049
	push	edx eax
1519 hidnplayr 2050
 
1529 hidnplayr 2051
;-----------------------------------------------
2052
; Fill in the TCP header by using the socket ptr
1519 hidnplayr 2053
 
1529 hidnplayr 2054
	mov	ax, [esi + TCP_SOCKET.LocalPort]
2055
	rol	ax, 8
2056
	stosw
2057
	mov	ax, [esi + TCP_SOCKET.RemotePort]
2058
	rol	ax, 8
2059
	stosw
2060
	mov	eax, [esi + TCP_SOCKET.SND_NXT]
2061
	bswap	eax
2062
	stosd
2063
	mov	eax, [esi + TCP_SOCKET.RCV_NXT]
2064
	bswap	eax
2065
	stosd
2066
	mov	al, 0x50	; Dataoffset: 20 bytes
2067
	stosb
2068
	mov	al, cl
2069
	stosb
2070
	mov	ax, [esi + TCP_SOCKET.RCV_WND]
2071
	rol	ax, 8
2072
	stosw			; window
2073
	xor	eax, eax
2074
	stosd			; checksum + urgentpointer
1519 hidnplayr 2075
 
2076
;---------------------
2077
; Fill in the checksum
2078
 
2079
  .checksum:
1529 hidnplayr 2080
	sub	edi, TCP_segment.Data
2081
	mov	ecx, TCP_segment.Data
2082
	xchg	esi, edi
2083
	TCP_checksum (edi + IP_SOCKET.LocalIP), (esi + IP_SOCKET.RemoteIP)
2084
	mov	[esi+TCP_segment.Checksum], dx
1519 hidnplayr 2085
 
2086
;--------------------
2087
; And send the segment
2088
 
2089
	call	[ebx + NET_DEVICE.transmit]
1159 hidnplayr 2090
	ret
2091
 
1519 hidnplayr 2092
  .error:
1529 hidnplayr 2093
	DEBUGF	1,"TCP_respond failed\n"
2094
	add	esp, 2+4
1159 hidnplayr 2095
 
1519 hidnplayr 2096
	ret
1514 hidnplayr 2097
 
1529 hidnplayr 2098
 
2099
 
2100
;-------------------------
2101
; TCP_respond.segment:
2102
;
2103
;  IN:  edx = segment ptr (a previously received segment)
2104
;        cl = flags
2105
 
2106
align 4
2107
TCP_respond_segment:
2108
 
2109
	DEBUGF	1,"TCP_respond_segment\n"
2110
 
2111
;---------------------
2112
; Create the IP packet
2113
 
2114
	push	cx edx
2115
	mov	ebx, [edx - 20 + IPv4_Packet.SourceAddress]	 ;;;; and what if ip packet had options?!
2116
	mov	eax, [edx - 20 + IPv4_Packet.DestinationAddress]   ;;;
2117
	mov	ecx, TCP_segment.Data
2118
	mov	di , IP_PROTO_TCP shl 8 + 128
2119
	call	IPv4_output
2120
	jz	.error
1533 hidnplayr 2121
	pop	esi cx
1529 hidnplayr 2122
 
2123
	push	edx eax
2124
 
1519 hidnplayr 2125
;---------------------------------------------------
2126
; Fill in the TCP header by using a received segment
2127
 
2128
	mov	ax, [esi + TCP_segment.DestinationPort]
2129
	rol	ax, 8
2130
	stosw
2131
	mov	ax, [esi + TCP_segment.SourcePort]
2132
	rol	ax, 8
2133
	stosw
2134
	mov	eax, [esi + TCP_segment.AckNumber]
2135
	bswap	eax
2136
	stosd
2137
	xor	eax, eax
2138
	stosd
2139
	mov	al, 0x50	; Dataoffset: 20 bytes
2140
	stosb
2141
	mov	al, cl
2142
	stosb
2143
	mov	ax, 1280
2144
	rol	ax, 8
2145
	stosw			; window
2146
	xor	eax, eax
2147
	stosd			; checksum + urgentpointer
2148
 
1529 hidnplayr 2149
;---------------------
2150
; Fill in the checksum
1519 hidnplayr 2151
 
1529 hidnplayr 2152
  .checksum:
2153
	lea	esi, [edi - TCP_segment.Data]
2154
	mov	ecx, TCP_segment.Data
2155
	TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress)
2156
	mov	[esi+TCP_segment.Checksum], dx
1519 hidnplayr 2157
 
1529 hidnplayr 2158
;--------------------
2159
; And send the segment
1519 hidnplayr 2160
 
1529 hidnplayr 2161
	call	[ebx + NET_DEVICE.transmit]
2162
	ret
1519 hidnplayr 2163
 
1529 hidnplayr 2164
  .error:
2165
	DEBUGF	1,"TCP_respond failed\n"
2166
	add	esp, 2+4
1519 hidnplayr 2167
 
2168
	ret
2169
 
2170
 
2171
 
1254 hidnplayr 2172
 
2173
;---------------------------------------------------------------------------
2174
;
2175
; TCP_API
2176
;
2177
; This function is called by system function 75
2178
;
2179
; IN:  subfunction number in bl
2180
;      device number in bh
2181
;      ecx, edx, .. depends on subfunction
2182
;
2183
; OUT:
2184
;
2185
;---------------------------------------------------------------------------
2186
align 4
2187
TCP_API:
2188
 
2189
	movzx	eax, bh
2190
	shl	eax, 2
2191
 
2192
	test	bl, bl
2193
	jz	.packets_tx	; 0
2194
	dec	bl
2195
	jz	.packets_rx	; 1
2196
 
2197
.error:
2198
	mov	eax, -1
2199
	ret
2200
 
2201
.packets_tx:
1514 hidnplayr 2202
	add	eax, TCP_segments_tx
1254 hidnplayr 2203
	mov	eax, [eax]
2204
	ret
2205
 
2206
.packets_rx:
1514 hidnplayr 2207
	add	eax, TCP_segments_rx
1254 hidnplayr 2208
	mov	eax, [eax]
2209
	ret