Subversion Repositories Kolibri OS

Rev

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