Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1196 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved.    ;;
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
;;                                                                 ;;
10
;;    Written by hidnplayr@kolibrios.org                           ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1159 hidnplayr 16
 
1196 hidnplayr 17
 
1206 hidnplayr 18
$Revision: 1254 $
1159 hidnplayr 19
 
1196 hidnplayr 20
TCP_RETRIES		equ 5		; Number of times to resend a Packet
1254 hidnplayr 21
TCP_PACKET_TTL		equ 50		; resend if not replied to in 1/100 s
22
TCP_SOCKET_TTL		equ 10		; # of secs to wait before closing socket
1159 hidnplayr 23
 
1196 hidnplayr 24
TCP_QUEUE_SIZE		equ 16
25
 
1249 hidnplayr 26
 
1159 hidnplayr 27
struct	TCP_Packet
28
	.SourcePort		dw ?
29
	.DestinationPort	dw ?
30
	.SequenceNumber 	dd ?
31
	.AckNumber		dd ?
1196 hidnplayr 32
	.DataOffset		db ?	; DataOffset[0-3 bits] and Reserved[4-7]
33
	.Flags			db ?	; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
1159 hidnplayr 34
	.Window 		dw ?
35
	.Checksum		dw ?
36
	.UrgentPointer		dw ?
37
	.Options		rb 3
38
	.Padding		db ?
39
	.Data:
40
ends
41
 
1196 hidnplayr 42
align 4
43
uglobal
44
	TCP_PACKETS_TX		rd  MAX_IP
45
	TCP_PACKETS_RX		rd  MAX_IP
1159 hidnplayr 46
 
1249 hidnplayr 47
	TCP_IN_QUEUE		rd  (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
1254 hidnplayr 48
	TCP_OUT_QUEUE		dd  ?
1249 hidnplayr 49
				rd  (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
1196 hidnplayr 50
endg
51
 
1249 hidnplayr 52
align 4
53
iglobal
1196 hidnplayr 54
 
1254 hidnplayr 55
stateHandler:
1196 hidnplayr 56
 
1249 hidnplayr 57
  dd  stateTCB_LISTEN
58
  dd  stateTCB_SYN_SENT
59
  dd  stateTCB_SYN_RECEIVED
60
  dd  stateTCB_ESTABLISHED
61
  dd  stateTCB_FIN_WAIT_1
62
  dd  stateTCB_FIN_WAIT_2
63
  dd  stateTCB_CLOSE_WAIT
64
  dd  stateTCB_CLOSING
65
  dd  stateTCB_LAST_ACK
66
  dd  stateTCB_TIME_WAIT
67
  dd  stateTCB_CLOSED
1196 hidnplayr 68
 
1249 hidnplayr 69
endg
1196 hidnplayr 70
 
1249 hidnplayr 71
 
1196 hidnplayr 72
;-----------------------------------------------------------------
73
;
74
; TCP_init
75
;
76
;  This function resets all TCP variables
77
;
78
;  IN:  /
79
;  OUT: /
80
;
81
;-----------------------------------------------------------------
82
 
83
align 4
84
TCP_init:
85
 
86
	xor	eax, eax
87
	mov	edi, TCP_PACKETS_TX
88
	mov	ecx, 2*MAX_IP
89
	rep	stosd
90
 
1249 hidnplayr 91
	init_queue TCP_IN_QUEUE
1196 hidnplayr 92
 
1254 hidnplayr 93
	; tcp_out_queue is a special type of queue
94
	xor	eax, eax
95
	mov	esi, TCP_OUT_QUEUE
96
	mov	ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+1
97
	rep	stosd
98
 
1196 hidnplayr 99
	ret
100
 
101
 
102
;-----------------------------------------------------------------
103
;
1249 hidnplayr 104
;  TCP_decrease_socket_ttls
1159 hidnplayr 105
;
1249 hidnplayr 106
;  IN:  /
107
;  OUT: /
1159 hidnplayr 108
;
1196 hidnplayr 109
;-----------------------------------------------------------------
1159 hidnplayr 110
 
1196 hidnplayr 111
align 4
1249 hidnplayr 112
TCP_decrease_socket_ttls:
1159 hidnplayr 113
	; scan through all the sockets, decrementing active timers
114
 
115
	mov	ebx, net_sockets
116
 
1249 hidnplayr 117
	cmp	[ebx + SOCKET_head.NextPtr], 0
1159 hidnplayr 118
	je	.exit
119
 
120
  .next_socket:
1249 hidnplayr 121
	mov	ebx, [ebx + SOCKET_head.NextPtr]
1159 hidnplayr 122
	or	ebx, ebx
123
	jz	.exit
124
 
1249 hidnplayr 125
	cmp	[ebx + SOCKET_head.Type], IP_PROTO_TCP
126
	jne	.next_socket
127
 
1254 hidnplayr 128
;        DEBUGF  1, "K :   %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.state]
1159 hidnplayr 129
 
1254 hidnplayr 130
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0
1159 hidnplayr 131
	jne	.decrement_tcb
1249 hidnplayr 132
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
1159 hidnplayr 133
	jne	.decrement_wnd
134
	jmp	.next_socket
135
 
136
  .decrement_tcb:
137
	; decrement it, delete socket if TCB timer = 0 & socket in timewait state
1254 hidnplayr 138
	dec	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer]
1159 hidnplayr 139
	jnz	.next_socket
140
 
1254 hidnplayr 141
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 142
	jne	.next_socket
143
 
1249 hidnplayr 144
	push	[ebx + SOCKET_head.PrevPtr]
1159 hidnplayr 145
	stdcall net_socket_free, ebx
146
	pop	ebx
147
	jmp	.next_socket
148
 
149
  .decrement_wnd:
150
	; TODO - prove it works!
1249 hidnplayr 151
	dec	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
1159 hidnplayr 152
	jmp	.next_socket
153
 
154
  .exit:
155
	ret
156
 
157
 
1249 hidnplayr 158
 
159
;-----------------------------------------------------------------
1159 hidnplayr 160
;
1249 hidnplayr 161
; TCP_send_queued:
1159 hidnplayr 162
;
1249 hidnplayr 163
;  Decreases 'ttl' of tcp packets queued.
164
;  if 'ttl' reaches 0, resend the packet and decrease 'retries'
165
;  if 'retries' reaches zero, remove the queued packet
166
;
167
;  IN:  /
168
;  OUT: /
169
;
170
;-----------------------------------------------------------------
1159 hidnplayr 171
 
1196 hidnplayr 172
align 4
1249 hidnplayr 173
TCP_send_queued:
1159 hidnplayr 174
 
1249 hidnplayr 175
	cmp	[TCP_OUT_QUEUE], 0
176
	je	.exit
1159 hidnplayr 177
 
1249 hidnplayr 178
	mov	eax, TCP_QUEUE_SIZE
179
	mov	ecx, [TCP_OUT_QUEUE]
180
	mov	esi, TCP_OUT_QUEUE+4
1159 hidnplayr 181
 
1249 hidnplayr 182
  .loop:
183
	cmp	[esi + tcp_out_queue_entry.data_ptr], 0
184
	jnz	.found_one
185
	add	esi, tcp_out_queue_entry.size
186
	loop	.loop
187
  .exit:
188
	ret
1159 hidnplayr 189
 
1249 hidnplayr 190
  .found_one:
191
	dec	[esi + tcp_out_queue_entry.ttl]
192
	jz	.send_it
193
  .find_next:
1254 hidnplayr 194
	add	esi, tcp_out_queue_entry.size
1249 hidnplayr 195
	dec	eax
196
	jz	.exit
1254 hidnplayr 197
	test	ecx, ecx
198
	jnz	.loop
199
	ret
1159 hidnplayr 200
 
1249 hidnplayr 201
  .send_it:
202
	push	eax ecx esi
1159 hidnplayr 203
 
1254 hidnplayr 204
	mov	ebx, [esi + tcp_out_queue_entry.owner]
1249 hidnplayr 205
	push	[esi + tcp_out_queue_entry.data_size]
206
	push	[esi + tcp_out_queue_entry.data_ptr]
1254 hidnplayr 207
	DEBUGF 1,"Now sending TCP packet %x, size: %u, owner: %x, sendproc %x\n", [esp], [esp+4], ebx, [esi + tcp_out_queue_entry.sendproc]
1249 hidnplayr 208
	call	[esi + tcp_out_queue_entry.sendproc]
1254 hidnplayr 209
	add	esp, 8
1249 hidnplayr 210
	pop	esi ecx eax
1159 hidnplayr 211
 
1249 hidnplayr 212
	dec	[esi + tcp_out_queue_entry.retries]
213
	jz	.remove_it
1254 hidnplayr 214
 
215
	mov	[esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL
1249 hidnplayr 216
	jmp	.find_next
1159 hidnplayr 217
 
1249 hidnplayr 218
  .remove_it:
219
	push	[esi + tcp_out_queue_entry.data_ptr]
220
	mov	[esi + tcp_out_queue_entry.data_ptr], 0
221
	call	kernel_free
222
	jmp	.find_next
1159 hidnplayr 223
 
224
 
225
 
1249 hidnplayr 226
;-----------------------------------------------------------------
227
;
228
; TCP_add_to_queue:
229
;
230
;  Queue a TCP packet for sending
231
;
232
;  IN:  [esp] pointer to buffer
233
;       [esp + 4] size of buffer
234
;       ebx = driver struct
235
;       esi = sender proc
236
;       edx = acknum
237
;  OUT: /
238
;
239
;-----------------------------------------------------------------
1159 hidnplayr 240
 
1249 hidnplayr 241
align 4
242
TCP_add_to_queue:
1159 hidnplayr 243
 
1254 hidnplayr 244
	DEBUGF 1,"Adding packet to TCP queue, buffer: %x, size: %u, driver: %x, acknum: %x\n", [esp], [esp+4], ebx, edx
245
 
1249 hidnplayr 246
	cmp	[TCP_OUT_QUEUE], TCP_QUEUE_SIZE
247
	jge	.full
1159 hidnplayr 248
 
1249 hidnplayr 249
	mov	ecx, TCP_QUEUE_SIZE
250
	mov	eax, TCP_OUT_QUEUE+4
1159 hidnplayr 251
 
1249 hidnplayr 252
  .loop:
253
	cmp	[eax + tcp_out_queue_entry.data_ptr], 0
254
	je	.found_it
255
	add	eax, tcp_out_queue_entry.size
256
	loop	.loop
1159 hidnplayr 257
 
1249 hidnplayr 258
  .full:			; silently discard the packet
1254 hidnplayr 259
 
260
	DEBUGF 1,"TCP queue is full!\n"
261
 
1249 hidnplayr 262
	call	kernel_free
263
	add	esp, 4
264
 
1159 hidnplayr 265
	ret
266
 
1249 hidnplayr 267
  .found_it:			; eax point to empty queue entry
1159 hidnplayr 268
 
1249 hidnplayr 269
	pop	[eax + tcp_out_queue_entry.data_ptr]
270
	pop	[eax + tcp_out_queue_entry.data_size]
271
	mov	[eax + tcp_out_queue_entry.ttl], 1			; send immediately
272
	mov	[eax + tcp_out_queue_entry.retries], TCP_RETRIES
273
	mov	[eax + tcp_out_queue_entry.owner], ebx
274
	mov	[eax + tcp_out_queue_entry.sendproc], esi
1254 hidnplayr 275
	mov	[eax + tcp_out_queue_entry.seq_num], edx
1196 hidnplayr 276
 
1254 hidnplayr 277
	inc	[TCP_OUT_QUEUE]
1249 hidnplayr 278
 
1254 hidnplayr 279
	sub	eax, TCP_OUT_QUEUE+4
280
	DEBUGF 1,"Added to queue in pos %u\n", eax
281
 
1249 hidnplayr 282
	ret
283
 
284
 
1196 hidnplayr 285
;-----------------------------------------------------------------
1159 hidnplayr 286
;
1249 hidnplayr 287
; TCP_handler:
1159 hidnplayr 288
;
1196 hidnplayr 289
;  Called by IPv4_handler,
290
;  this procedure will inject the tcp data diagrams in the application sockets.
291
;
292
;  IN:  Pointer to buffer in [esp]
293
;       size of buffer in [esp+4]
294
;       pointer to device struct in ebx
295
;       TCP Packet size in ecx
296
;       pointer to TCP Packet data in edx
297
;       SourceAddres in esi
298
;  OUT: /
299
;
300
;-----------------------------------------------------------------
1159 hidnplayr 301
 
1249 hidnplayr 302
align 4
303
TCP_handler :
1159 hidnplayr 304
 
1196 hidnplayr 305
       DEBUGF 1,"TCP_Handler\n"
306
 
1254 hidnplayr 307
	; TODO: validate checksum
308
 
1159 hidnplayr 309
	; IP Packet TCP Destination Port = local Port
1249 hidnplayr 310
	; IP Packet SA = Remote IP  OR = 0
311
	; IP Packet TCP Source Port = remote Port  OR = 0
1159 hidnplayr 312
 
313
	mov	ebx, net_sockets
314
 
1249 hidnplayr 315
  .socket_loop:
316
	mov	ebx, [ebx + SOCKET_head.NextPtr]
1159 hidnplayr 317
	or	ebx, ebx
1249 hidnplayr 318
	jz	.dump
1159 hidnplayr 319
 
1249 hidnplayr 320
	mov	ax, [edx + TCP_Packet.DestinationPort]
321
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
322
	jne	.socket_loop
1159 hidnplayr 323
 
1249 hidnplayr 324
	mov	eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
325
	cmp	eax, esi
326
	je	@f
327
	test	eax, eax
328
	jne	.socket_loop
329
       @@:
1159 hidnplayr 330
 
1249 hidnplayr 331
	mov	ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
332
	cmp	[edx + TCP_Packet.SourcePort] , ax
333
	je	.change_state
334
	test	ax, ax
1254 hidnplayr 335
	jnz	.socket_loop
1159 hidnplayr 336
 
1249 hidnplayr 337
  .change_state:
1159 hidnplayr 338
 
1254 hidnplayr 339
       DEBUGF 1,"Found valid socket for packet\n"
340
 
1249 hidnplayr 341
	push	ebx
342
	lea	ebx, [ebx + SOCKET_head.lock]
343
	call	wait_mutex
344
	pop	ebx
1159 hidnplayr 345
 
1249 hidnplayr 346
;----------------------------------
347
; ebx is pointer to socket
348
; ecx is size of tcp packet
349
; edx is pointer to tcp packet
1159 hidnplayr 350
 
1249 hidnplayr 351
	; as a Packet has been received, update the TCB timer
1254 hidnplayr 352
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], TCP_SOCKET_TTL
1159 hidnplayr 353
 
1249 hidnplayr 354
	; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
355
	test	[edx + TCP_Packet.Flags], TH_ACK
356
	jz	.call_handler					; No ACK, so no data yet
1159 hidnplayr 357
 
1254 hidnplayr 358
;        mov     eax, [edx + TCP_Packet.SequenceNumber]          ; Calculate sequencenumber in eax
359
;        bswap   eax                                             ;
360
;        add     eax, ecx                                        ;
1159 hidnplayr 361
 
1254 hidnplayr 362
	mov	eax, [edx + TCP_Packet.AckNumber]
363
	;---------
364
 
1249 hidnplayr 365
	cmp	[TCP_OUT_QUEUE], 0
366
	je	.call_handler
1254 hidnplayr 367
	push	ecx
1159 hidnplayr 368
 
1254 hidnplayr 369
       DEBUGF 1,"Removing all queued packets with smaller ACK\n"
370
 
1249 hidnplayr 371
	mov	ecx, TCP_QUEUE_SIZE
372
	mov	esi, TCP_OUT_QUEUE+4
1159 hidnplayr 373
 
1249 hidnplayr 374
  .loop:
375
	cmp	[esi + tcp_out_queue_entry.data_ptr], 0
1254 hidnplayr 376
	je	.maybe_next
377
	cmp	[esi + tcp_out_queue_entry.seq_num], eax
1249 hidnplayr 378
	jg	.maybe_next
1254 hidnplayr 379
	; TODO: check if the packets belong to the same tcp connection !
1159 hidnplayr 380
 
1254 hidnplayr 381
       DEBUGF 1,"Removing a queued packet\n"
382
 
1249 hidnplayr 383
	push	[esi + tcp_out_queue_entry.data_ptr]
384
	mov	[esi + tcp_out_queue_entry.data_ptr], 0
385
	dec	[TCP_OUT_QUEUE]
386
	call	kernel_free
1159 hidnplayr 387
 
1249 hidnplayr 388
  .maybe_next:
389
	add	esi, tcp_out_queue_entry.size
390
	loop	.loop
1254 hidnplayr 391
 
1249 hidnplayr 392
	pop	ecx
393
  .call_handler:
394
	; Call handler for given TCB state
1254 hidnplayr 395
	mov	eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
396
	DEBUGF 1,"Socket state: %u\n", eax
397
 
1249 hidnplayr 398
	cmp	eax, TCB_LISTEN
1254 hidnplayr 399
	jb	.dump
1249 hidnplayr 400
	cmp	eax, TCB_CLOSED
1254 hidnplayr 401
	ja	.dump
1159 hidnplayr 402
 
1254 hidnplayr 403
	dec	eax
1249 hidnplayr 404
	shl	eax, 2
1254 hidnplayr 405
	add	eax, stateHandler
1159 hidnplayr 406
 
1254 hidnplayr 407
	call	dword[eax]
1159 hidnplayr 408
 
1249 hidnplayr 409
  .dump:
410
	DEBUGF 1,"Dumping TCP packet\n"
1196 hidnplayr 411
	call	kernel_free
412
	add	esp, 4 ; pop (balance stack)
1159 hidnplayr 413
 
1249 hidnplayr 414
	ret
1196 hidnplayr 415
 
416
 
417
 
418
;-----------------------------------------------------------------
419
;
1249 hidnplayr 420
; TCP_socket_send
1196 hidnplayr 421
;
1249 hidnplayr 422
; IN: eax = socket pointer
423
;     ecx = number of bytes to send
424
;     esi = pointer to data
425
;
1196 hidnplayr 426
;-----------------------------------------------------------------
427
 
1249 hidnplayr 428
align 4
429
TCP_socket_send:
1196 hidnplayr 430
 
1249 hidnplayr 431
	DEBUGF 1,"Creating TCP Packet\n"
1159 hidnplayr 432
 
1249 hidnplayr 433
	mov	di , IP_PROTO_TCP
1159 hidnplayr 434
 
1249 hidnplayr 435
; Create an IPv4 Packet of the correct size
436
	push	eax
437
	mov	ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
438
	mov	eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
1159 hidnplayr 439
 
1249 hidnplayr 440
; meanwhile, create the pseudoheader in stack,
441
; (now that we still have all the variables that are needed.)
442
	push	cx
443
	push	di
1159 hidnplayr 444
	push	eax
1249 hidnplayr 445
	push	ebx
1159 hidnplayr 446
 
447
 
1249 hidnplayr 448
	push	ecx esi eax		; save some variables for later
1254 hidnplayr 449
	add	ecx, TCP_Packet.Options
1249 hidnplayr 450
	call	IPv4_create_packet
451
	cmp	edi, -1
452
	je	.fail
1159 hidnplayr 453
 
1249 hidnplayr 454
	pop	esi
1159 hidnplayr 455
 
1249 hidnplayr 456
; Now add the TCP header to the IPv4 packet
1159 hidnplayr 457
 
1249 hidnplayr 458
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
459
	pop	[edi + TCP_Packet.SequenceNumber]
1159 hidnplayr 460
 
1249 hidnplayr 461
	push	dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
462
	pop	dword [edi + TCP_Packet.SourcePort]
1159 hidnplayr 463
 
464
 
1249 hidnplayr 465
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
466
	pop	[edi + TCP_Packet.AckNumber]
1159 hidnplayr 467
 
1249 hidnplayr 468
	mov	al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
469
	mov	[edi + TCP_Packet.Flags], al
1159 hidnplayr 470
 
1254 hidnplayr 471
	mov	[edi + TCP_Packet.Window], 0x0005	   ; 1280 bytes
1249 hidnplayr 472
	mov	[edi + TCP_Packet.UrgentPointer], 0
473
	mov	[edi + TCP_Packet.DataOffset], 0x50
474
	mov	[edi + TCP_Packet.Checksum], 0
1159 hidnplayr 475
 
1249 hidnplayr 476
; Copy the data
477
	mov	esi, [esp]
478
	mov	ecx, [esp+4]
1254 hidnplayr 479
	add	edi, TCP_Packet.Options
1159 hidnplayr 480
 
1249 hidnplayr 481
	shr	ecx, 1
482
	jnc	.nb
483
	movsb
484
.nb:	shr	ecx, 1
485
	jnc	.nw
486
	movsw
487
.nw:	rep movsd
1159 hidnplayr 488
 
1249 hidnplayr 489
; Now, calculate the checksum for pseudoheader
490
	xor	edx, edx
491
	mov	ecx, 12
492
	mov	esi, esp
493
	call	checksum_1
494
	add	esp, 12 				   ; remove the pseudoheader from stack
495
; And that of the data
496
	pop	esi
497
	pop	ecx
498
	call	checksum_1
499
; Now create the final checksum and store it in TCP header
500
	call	checksum_2
501
	mov	[edi + TCP_Packet.Checksum], dx
1159 hidnplayr 502
 
1249 hidnplayr 503
; And now, send it!
504
	DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
1254 hidnplayr 505
	lea	esi, [ebx+ETH_DEVICE.transmit]
1249 hidnplayr 506
	mov	edx, [edi + TCP_Packet.AckNumber]
507
	jmp	TCP_add_to_queue
1159 hidnplayr 508
 
1249 hidnplayr 509
  .fail:
1254 hidnplayr 510
	add	esp, 12+12+4
1159 hidnplayr 511
	ret
512
 
513
 
514
 
515
 
516
 
1249 hidnplayr 517
;-----------------------------------------------------------------
1159 hidnplayr 518
;
1249 hidnplayr 519
; TCP_send_ack
1159 hidnplayr 520
;
1249 hidnplayr 521
; IN: eax = socket pointer
522
;      bl = flags
1159 hidnplayr 523
;
1249 hidnplayr 524
;-----------------------------------------------------------------
1159 hidnplayr 525
 
1249 hidnplayr 526
align 4
527
TCP_send_ack:
1159 hidnplayr 528
 
1254 hidnplayr 529
	DEBUGF 1,"Creating TCP ACK, socket: %x, flags: %x\n",eax, bl
1159 hidnplayr 530
 
1249 hidnplayr 531
	mov	di , IP_PROTO_TCP
1254 hidnplayr 532
	mov	ecx, TCP_Packet.Options
1159 hidnplayr 533
 
1249 hidnplayr 534
	push	bx eax
1159 hidnplayr 535
 
1249 hidnplayr 536
; Create an IPv4 Packet of the correct size
1254 hidnplayr 537
 
1249 hidnplayr 538
	mov	ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
539
	mov	eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
1159 hidnplayr 540
 
1249 hidnplayr 541
	call	IPv4_create_packet
542
	cmp	edi, -1
543
	je	.fail
1159 hidnplayr 544
 
1249 hidnplayr 545
; Fill in the TCP header
546
	pop	esi
1159 hidnplayr 547
 
1249 hidnplayr 548
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
549
	pop	[edi + TCP_Packet.SequenceNumber]
1159 hidnplayr 550
 
1254 hidnplayr 551
	push	dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] ; both ports at once
1249 hidnplayr 552
	pop	dword [edi + TCP_Packet.SourcePort]
1159 hidnplayr 553
 
1254 hidnplayr 554
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
1249 hidnplayr 555
	pop	[edi + TCP_Packet.AckNumber]
1159 hidnplayr 556
 
1249 hidnplayr 557
	pop	cx
558
	mov	[edi + TCP_Packet.Flags], cl
559
	mov	[edi + TCP_Packet.Window], 0x0005	   ; 1280 bytes
560
	mov	[edi + TCP_Packet.UrgentPointer], 0
561
	mov	[edi + TCP_Packet.DataOffset], 0x50
1254 hidnplayr 562
	mov	[edi + TCP_Packet.Checksum], 0
1159 hidnplayr 563
 
1254 hidnplayr 564
	push	edx eax
1159 hidnplayr 565
 
1254 hidnplayr 566
	lea	esi, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
567
	inc_INET esi
1159 hidnplayr 568
 
1254 hidnplayr 569
; Now, calculate the checksum
570
	pushw	TCP_Packet.Options shl 8
571
	pushw	IP_PROTO_TCP shl 8
572
	pushd	[edi-4] ; destination address
573
	pushd	[edi-8] ; source address
574
 
1249 hidnplayr 575
	xor	edx, edx
1254 hidnplayr 576
	mov	ecx, TCP_Packet.Options
577
	mov	esi, edi
578
	call	checksum_1
1249 hidnplayr 579
	mov	ecx, 12
580
	mov	esi, esp
581
	call	checksum_1
582
	add	esp, 12 				   ; remove the pseudoheader from stack
1254 hidnplayr 583
; and store it in TCP header
1249 hidnplayr 584
	call	checksum_2
585
	mov	[edi + TCP_Packet.Checksum], dx
1159 hidnplayr 586
 
1254 hidnplayr 587
; And now, send the packet!
1249 hidnplayr 588
	DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
1254 hidnplayr 589
	mov	esi, [ebx + ETH_DEVICE.transmit]
590
	mov	edx, [edi + TCP_Packet.SequenceNumber]
1249 hidnplayr 591
	jmp	TCP_add_to_queue
1159 hidnplayr 592
 
1249 hidnplayr 593
  .fail:
1254 hidnplayr 594
	add	esp, 2+4
1249 hidnplayr 595
	ret
1159 hidnplayr 596
 
597
 
598
 
599
 
600
 
1249 hidnplayr 601
align 4
602
stateTCB_LISTEN:
1254 hidnplayr 603
 
604
	DEBUGF	1,"TCBStateHandler: Listen\n"
605
 
1159 hidnplayr 606
	; In this case, we are expecting a SYN Packet
607
	; For now, if the Packet is a SYN, process it, and send a response
608
	; If not, ignore it
609
 
610
	; Look at control flags
1249 hidnplayr 611
	test	[edx + TCP_Packet.Flags], TH_SYN
1159 hidnplayr 612
	jz	.exit
613
 
614
	; We have a SYN. update the socket with this IP Packets details,
615
	; And send a response
616
 
1249 hidnplayr 617
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
618
	mov	ax, [edx + TCP_Packet.SourcePort]
619
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax
620
	mov	eax, [edx + TCP_Packet.SequenceNumber]
621
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
622
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
623
	lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
624
	inc_INET esi ; RCV.NXT
625
	mov	eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
626
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax
1159 hidnplayr 627
 
1254 hidnplayr 628
	mov	[ebx + SOCKET_head.lock], 0
629
 
1249 hidnplayr 630
	; Now construct the response
1159 hidnplayr 631
	mov	bl, TH_SYN + TH_ACK
1249 hidnplayr 632
	call	TCP_send_ack
1159 hidnplayr 633
 
1254 hidnplayr 634
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
1159 hidnplayr 635
 
636
	; increment SND.NXT in socket
1249 hidnplayr 637
	lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
638
	inc_INET esi
1159 hidnplayr 639
 
640
  .exit:
1254 hidnplayr 641
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 642
	ret
643
 
644
 
1249 hidnplayr 645
align 4
646
stateTCB_SYN_SENT:
1254 hidnplayr 647
 
648
	DEBUGF	1,"TCBStateHandler: Syn_Sent\n"
649
 
1159 hidnplayr 650
	; We are awaiting an ACK to our SYN, with a SYM
651
	; Look at control flags - expecting an ACK
652
 
1249 hidnplayr 653
	mov	al, [edx + TCP_Packet.Flags]
1159 hidnplayr 654
	and	al, TH_SYN + TH_ACK
655
	cmp	al, TH_SYN + TH_ACK
656
	je	.syn_ack
657
 
658
	test	al, TH_SYN
659
	jz	.exit
660
 
1254 hidnplayr 661
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
662
	pushd	TH_SYN + TH_ACK
1159 hidnplayr 663
	jmp	.send
664
 
665
  .syn_ack:
1254 hidnplayr 666
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
667
	pushd	TH_ACK
1159 hidnplayr 668
 
669
  .send:
670
	; Store the recv.nxt field
1249 hidnplayr 671
	mov	eax, [edx + TCP_Packet.SequenceNumber]
1254 hidnplayr 672
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
673
	bswap	eax
674
	inc	eax
675
	bswap	eax
676
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax	      ; Update our recv.nxt field
677
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 678
 
679
	; Send an ACK
1254 hidnplayr 680
	mov	eax, ebx
1159 hidnplayr 681
	pop	ebx
1249 hidnplayr 682
	call	TCP_send_ack
1159 hidnplayr 683
 
684
  .exit:
1254 hidnplayr 685
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 686
	ret
687
 
688
 
1249 hidnplayr 689
 
690
align 4
691
stateTCB_SYN_RECEIVED:
1254 hidnplayr 692
 
693
	DEBUGF	1,"TCBStateHandler: Syn_received\n"
694
 
1159 hidnplayr 695
	; In this case, we are expecting an ACK Packet
696
	; For now, if the Packet is an ACK, process it,
697
	; If not, ignore it
698
 
1249 hidnplayr 699
	test	[edx + TCP_Packet.Flags], TH_RST
1159 hidnplayr 700
	jz	.check_ack
701
 
1254 hidnplayr 702
  ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
703
 ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
704
  ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
705
 ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
1159 hidnplayr 706
 
1254 hidnplayr 707
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
1159 hidnplayr 708
	jmp	.exit
709
 
710
  .check_ack:
711
	; Look at control flags - expecting an ACK
1249 hidnplayr 712
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 713
	jz	.exit
714
 
1254 hidnplayr 715
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
1159 hidnplayr 716
 
717
  .exit:
1254 hidnplayr 718
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 719
	ret
720
 
721
 
1249 hidnplayr 722
 
723
align 4
724
stateTCB_ESTABLISHED:
1254 hidnplayr 725
 
726
 
727
	DEBUGF	1,"TCBStateHandler: Established\n"
728
 
1159 hidnplayr 729
	; Here we are expecting data, or a request to close
730
	; OR both...
731
 
732
	; Did we receive a FIN or RST?
1249 hidnplayr 733
	test	[edx + TCP_Packet.Flags], TH_FIN
1159 hidnplayr 734
	jz	.check_ack
735
 
736
	; It was a fin or reset.
737
 
1254 hidnplayr 738
;;; TODO: write following code:
1159 hidnplayr 739
	; Remove resend entries from the queue  - I dont want to send any more data
1249 hidnplayr 740
	; Send an ACK to that fin, and enter closewait state
1159 hidnplayr 741
 
742
  .check_ack:
743
	; Check that we received an ACK
1249 hidnplayr 744
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 745
	jz	.exit
746
 
1254 hidnplayr 747
	DEBUGF	1,"Received ACK\n"
748
 
1159 hidnplayr 749
	; First, look at the incoming window. If this is less than or equal to 1024,
750
	; Set the socket window timer to 1. This will stop an additional Packets being queued.
751
	; ** I may need to tweak this value, since I do not know how many Packets are already queued
1249 hidnplayr 752
	mov	cx, [edx + TCP_Packet.Window]
1159 hidnplayr 753
	xchg	cl, ch
754
	cmp	cx, 1024
755
	ja	@f
756
 
1249 hidnplayr 757
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
1159 hidnplayr 758
 
759
    @@: ; OK, here is the deal
760
	; My recv.nct field holds the seq of the expected next rec byte
761
	; if the recevied sequence number is not equal to this, do not
762
	; increment the recv.nxt field, do not copy data - just send a
763
	; repeat ack.
764
 
765
	; recv.nxt is in dword [edx+24], in inet format
766
	; recv seq is in [sktAddr]+56, in inet format
767
	; just do a comparision
1249 hidnplayr 768
	mov	ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
1254 hidnplayr 769
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
1159 hidnplayr 770
	jne	@f
771
	mov	ecx, eax
772
 
1249 hidnplayr 773
    @@: cmp	ecx, [edx + TCP_Packet.SequenceNumber]
1159 hidnplayr 774
	jne	.ack
775
 
1249 hidnplayr 776
	test	ecx, ecx
777
	jnz	.data
1159 hidnplayr 778
 
779
	; If we had received a fin, we need to ACK it.
1254 hidnplayr 780
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
1159 hidnplayr 781
	je	.ack
782
	jmp	.exit
783
 
784
  .data:
1254 hidnplayr 785
	DEBUGF	1,"Got data!\n"
1249 hidnplayr 786
	mov	esi, [esp + 4]
787
	sub	edx, esi
788
	mov	edi, edx
789
	call	socket_internal_receiver
1159 hidnplayr 790
 
791
  .ack:
1254 hidnplayr 792
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 793
	; Send an ACK
1254 hidnplayr 794
	mov	eax, ebx
1159 hidnplayr 795
	mov	bl, TH_ACK
1249 hidnplayr 796
	call	TCP_send_ack
1159 hidnplayr 797
  .exit:
1254 hidnplayr 798
 
799
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 800
	ret
801
 
802
 
1249 hidnplayr 803
 
804
align 4
805
stateTCB_FIN_WAIT_1:
1254 hidnplayr 806
 
807
	DEBUGF	1,"TCBStateHandler: Fin_wait_1\n"
808
 
1159 hidnplayr 809
	; We can either receive an ACK of a fin, or a fin
1249 hidnplayr 810
	mov	al, [edx + TCP_Packet.Flags]
1159 hidnplayr 811
	and	al, TH_FIN + TH_ACK
812
 
813
	cmp	al, TH_ACK
814
	jne	@f
815
 
816
	; It was an ACK
1254 hidnplayr 817
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
1159 hidnplayr 818
	jmp	.exit
819
 
1254 hidnplayr 820
    @@: mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
1159 hidnplayr 821
	cmp	al, TH_FIN
822
	je	@f
1254 hidnplayr 823
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 824
 
1249 hidnplayr 825
    @@: lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
826
	inc_INET esi
1254 hidnplayr 827
 
828
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 829
	; Send an ACK
1254 hidnplayr 830
	mov	eax, ebx
1159 hidnplayr 831
	mov	bl, TH_ACK
1249 hidnplayr 832
	call	TCP_send_ack
1159 hidnplayr 833
 
834
  .exit:
1254 hidnplayr 835
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 836
	ret
837
 
838
 
1249 hidnplayr 839
 
840
align 4
841
stateTCB_FIN_WAIT_2:
1254 hidnplayr 842
 
843
	DEBUGF	1,"TCBStateHandler: Fin_wait_2\n"
844
 
1249 hidnplayr 845
	test	[edx + TCP_Packet.Flags], TH_FIN
1159 hidnplayr 846
	jz	.exit
847
 
848
	; Change state, as we have a fin
1254 hidnplayr 849
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 850
 
1249 hidnplayr 851
	lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
852
	inc_INET esi
1159 hidnplayr 853
 
1254 hidnplayr 854
	mov	[ebx + SOCKET_head.lock], 0
855
 
1159 hidnplayr 856
	; Send an ACK
1254 hidnplayr 857
	mov	eax, ebx
1159 hidnplayr 858
	mov	bl, TH_ACK
1249 hidnplayr 859
	call	TCP_send_ack
1159 hidnplayr 860
 
861
  .exit:
1254 hidnplayr 862
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 863
	ret
864
 
865
 
1249 hidnplayr 866
 
867
align 4
868
stateTCB_CLOSE_WAIT:
1254 hidnplayr 869
 
870
	DEBUGF	1,"TCBStateHandler: close_wait\n"
1159 hidnplayr 871
	; Intentionally left empty
872
	; socket_close_tcp handles this
1254 hidnplayr 873
 
874
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 875
	ret
876
 
877
 
1249 hidnplayr 878
 
879
align 4
880
stateTCB_CLOSING:
1254 hidnplayr 881
 
882
	DEBUGF	1,"TCBStateHandler: closingn\n"
883
 
1159 hidnplayr 884
	; We can either receive an ACK of a fin, or a fin
1249 hidnplayr 885
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 886
	jz	.exit
887
 
1254 hidnplayr 888
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 889
 
890
  .exit:
1254 hidnplayr 891
 
892
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 893
	ret
894
 
895
 
1249 hidnplayr 896
align 4
897
stateTCB_LAST_ACK:
1254 hidnplayr 898
 
899
	DEBUGF	1,"TCBStateHandler: last_ackn\n"
900
 
1159 hidnplayr 901
	; Look at control flags - expecting an ACK
1249 hidnplayr 902
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 903
	jz	.exit
904
 
1254 hidnplayr 905
	mov	[ebx + SOCKET_head.lock], 0
906
 
1159 hidnplayr 907
	; delete the socket
908
	stdcall net_socket_free, ebx
909
 
910
  .exit:
911
	ret
912
 
913
 
1249 hidnplayr 914
align 4
915
stateTCB_TIME_WAIT:
1254 hidnplayr 916
 
917
	DEBUGF	1,"TCBStateHandler: time_wait\n"
918
 
919
	mov	[ebx + SOCKET_head.lock], 0
920
 
1159 hidnplayr 921
	ret
922
 
923
 
1249 hidnplayr 924
align 4
925
stateTCB_CLOSED:
1254 hidnplayr 926
 
927
	DEBUGF	1,"TCBStateHandler: closed\n"
928
 
929
	mov	[ebx + SOCKET_head.lock], 0
930
 
1159 hidnplayr 931
	ret
932
 
933
 
934
 
1254 hidnplayr 935
;---------------------------------------------------------------------------
936
;
937
; TCP_API
938
;
939
; This function is called by system function 75
940
;
941
; IN:  subfunction number in bl
942
;      device number in bh
943
;      ecx, edx, .. depends on subfunction
944
;
945
; OUT:
946
;
947
;---------------------------------------------------------------------------
1159 hidnplayr 948
 
1254 hidnplayr 949
align 4
950
TCP_API:
951
 
952
	movzx	eax, bh
953
	shl	eax, 2
954
 
955
	test	bl, bl
956
	jz	.packets_tx	; 0
957
	dec	bl
958
	jz	.packets_rx	; 1
959
 
960
.error:
961
	mov	eax, -1
962
	ret
963
 
964
.packets_tx:
965
	add	eax, TCP_PACKETS_TX
966
	mov	eax, [eax]
967
	ret
968
 
969
.packets_rx:
970
	add	eax, TCP_PACKETS_RX
971
	mov	eax, [eax]
972
	ret