Subversion Repositories Kolibri OS

Rev

Rev 1256 | 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: 1257 $
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 ?
36
	.Options		rb 3
37
	.Padding		db ?
38
	.Data:
39
ends
40
 
1196 hidnplayr 41
align 4
42
uglobal
43
	TCP_PACKETS_TX		rd  MAX_IP
44
	TCP_PACKETS_RX		rd  MAX_IP
1159 hidnplayr 45
 
1249 hidnplayr 46
	TCP_IN_QUEUE		rd  (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
1254 hidnplayr 47
	TCP_OUT_QUEUE		dd  ?
1249 hidnplayr 48
				rd  (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
1196 hidnplayr 49
endg
50
 
1249 hidnplayr 51
align 4
52
iglobal
1254 hidnplayr 53
stateHandler:
1196 hidnplayr 54
 
1249 hidnplayr 55
  dd  stateTCB_LISTEN
56
  dd  stateTCB_SYN_SENT
57
  dd  stateTCB_SYN_RECEIVED
58
  dd  stateTCB_ESTABLISHED
59
  dd  stateTCB_FIN_WAIT_1
60
  dd  stateTCB_FIN_WAIT_2
61
  dd  stateTCB_CLOSE_WAIT
62
  dd  stateTCB_CLOSING
63
  dd  stateTCB_LAST_ACK
64
  dd  stateTCB_TIME_WAIT
65
  dd  stateTCB_CLOSED
1196 hidnplayr 66
 
1249 hidnplayr 67
endg
1196 hidnplayr 68
 
1249 hidnplayr 69
 
1196 hidnplayr 70
;-----------------------------------------------------------------
71
;
72
; TCP_init
73
;
74
;  This function resets all TCP variables
75
;
76
;  IN:  /
77
;  OUT: /
78
;
79
;-----------------------------------------------------------------
80
align 4
81
TCP_init:
82
 
83
	xor	eax, eax
84
	mov	edi, TCP_PACKETS_TX
85
	mov	ecx, 2*MAX_IP
86
	rep	stosd
87
 
1249 hidnplayr 88
	init_queue TCP_IN_QUEUE
1196 hidnplayr 89
 
1257 hidnplayr 90
	; tcp_out_queue is a special type of queue:
91
	; The first dword is a counter of total packets queued.
92
	; The remaining bytes are socket 'slots' wich use tcp_out_queue_entry data structure.
93
	; An empty slot is know by the fact that tcp_out_queue_entry.data_ptr (first dword of the slot) is set to 0
94
	; There are TCP_OUT_QUEUE_SIZE number of slots
95
 
1254 hidnplayr 96
	xor	eax, eax
97
	mov	esi, TCP_OUT_QUEUE
98
	mov	ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+1
99
	rep	stosd
100
 
1196 hidnplayr 101
	ret
102
 
103
 
104
;-----------------------------------------------------------------
105
;
1249 hidnplayr 106
;  TCP_decrease_socket_ttls
1159 hidnplayr 107
;
1249 hidnplayr 108
;  IN:  /
109
;  OUT: /
1159 hidnplayr 110
;
1196 hidnplayr 111
;-----------------------------------------------------------------
112
align 4
1249 hidnplayr 113
TCP_decrease_socket_ttls:
1159 hidnplayr 114
	; scan through all the sockets, decrementing active timers
115
 
116
	mov	ebx, net_sockets
117
 
1249 hidnplayr 118
	cmp	[ebx + SOCKET_head.NextPtr], 0
1159 hidnplayr 119
	je	.exit
120
 
121
  .next_socket:
1249 hidnplayr 122
	mov	ebx, [ebx + SOCKET_head.NextPtr]
1159 hidnplayr 123
	or	ebx, ebx
124
	jz	.exit
125
 
1249 hidnplayr 126
	cmp	[ebx + SOCKET_head.Type], IP_PROTO_TCP
127
	jne	.next_socket
128
 
1254 hidnplayr 129
;        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 130
 
1254 hidnplayr 131
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0
1159 hidnplayr 132
	jne	.decrement_tcb
1249 hidnplayr 133
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
1159 hidnplayr 134
	jne	.decrement_wnd
135
	jmp	.next_socket
136
 
137
  .decrement_tcb:
138
	; decrement it, delete socket if TCB timer = 0 & socket in timewait state
1254 hidnplayr 139
	dec	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer]
1159 hidnplayr 140
	jnz	.next_socket
141
 
1254 hidnplayr 142
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 143
	jne	.next_socket
144
 
1249 hidnplayr 145
	push	[ebx + SOCKET_head.PrevPtr]
1159 hidnplayr 146
	stdcall net_socket_free, ebx
147
	pop	ebx
148
	jmp	.next_socket
149
 
150
  .decrement_wnd:
151
	; TODO - prove it works!
1249 hidnplayr 152
	dec	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
1159 hidnplayr 153
	jmp	.next_socket
154
 
155
  .exit:
156
	ret
157
 
158
 
1249 hidnplayr 159
 
160
;-----------------------------------------------------------------
1159 hidnplayr 161
;
1249 hidnplayr 162
; TCP_send_queued:
1159 hidnplayr 163
;
1249 hidnplayr 164
;  Decreases 'ttl' of tcp packets queued.
165
;  if 'ttl' reaches 0, resend the packet and decrease 'retries'
166
;  if 'retries' reaches zero, remove the queued packet
167
;
168
;  IN:  /
169
;  OUT: /
170
;
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]
1257 hidnplayr 208
	inc	[TCP_PACKETS_TX]
1249 hidnplayr 209
	call	[esi + tcp_out_queue_entry.sendproc]
1254 hidnplayr 210
	add	esp, 8
1249 hidnplayr 211
	pop	esi ecx eax
1159 hidnplayr 212
 
1249 hidnplayr 213
	dec	[esi + tcp_out_queue_entry.retries]
214
	jz	.remove_it
1254 hidnplayr 215
 
216
	mov	[esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL
1249 hidnplayr 217
	jmp	.find_next
1159 hidnplayr 218
 
1249 hidnplayr 219
  .remove_it:
220
	push	[esi + tcp_out_queue_entry.data_ptr]
221
	mov	[esi + tcp_out_queue_entry.data_ptr], 0
222
	call	kernel_free
223
	jmp	.find_next
1159 hidnplayr 224
 
225
 
226
 
1249 hidnplayr 227
;-----------------------------------------------------------------
228
;
229
; TCP_add_to_queue:
230
;
231
;  Queue a TCP packet for sending
232
;
233
;  IN:  [esp] pointer to buffer
234
;       [esp + 4] size of buffer
235
;       ebx = driver struct
236
;       esi = sender proc
237
;       edx = acknum
238
;  OUT: /
239
;
240
;-----------------------------------------------------------------
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
;-----------------------------------------------------------------
1249 hidnplayr 301
align 4
302
TCP_handler :
1159 hidnplayr 303
 
1196 hidnplayr 304
       DEBUGF 1,"TCP_Handler\n"
305
 
1254 hidnplayr 306
	; TODO: validate checksum
307
 
1159 hidnplayr 308
	; IP Packet TCP Destination Port = local Port
1249 hidnplayr 309
	; IP Packet SA = Remote IP  OR = 0
310
	; IP Packet TCP Source Port = remote Port  OR = 0
1159 hidnplayr 311
 
312
	mov	ebx, net_sockets
313
 
1249 hidnplayr 314
  .socket_loop:
315
	mov	ebx, [ebx + SOCKET_head.NextPtr]
1159 hidnplayr 316
	or	ebx, ebx
1249 hidnplayr 317
	jz	.dump
1159 hidnplayr 318
 
1249 hidnplayr 319
	mov	ax, [edx + TCP_Packet.DestinationPort]
320
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
321
	jne	.socket_loop
1159 hidnplayr 322
 
1249 hidnplayr 323
	mov	eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
324
	cmp	eax, esi
325
	je	@f
326
	test	eax, eax
327
	jne	.socket_loop
328
       @@:
1159 hidnplayr 329
 
1249 hidnplayr 330
	mov	ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
331
	cmp	[edx + TCP_Packet.SourcePort] , ax
332
	je	.change_state
333
	test	ax, ax
1254 hidnplayr 334
	jnz	.socket_loop
1159 hidnplayr 335
 
1249 hidnplayr 336
  .change_state:
1159 hidnplayr 337
 
1254 hidnplayr 338
       DEBUGF 1,"Found valid socket for packet\n"
339
 
1257 hidnplayr 340
	inc	[TCP_PACKETS_RX]
341
 
1249 hidnplayr 342
	push	ebx
343
	lea	ebx, [ebx + SOCKET_head.lock]
344
	call	wait_mutex
345
	pop	ebx
1159 hidnplayr 346
 
1249 hidnplayr 347
;----------------------------------
348
; ebx is pointer to socket
349
; ecx is size of tcp packet
350
; edx is pointer to tcp packet
1159 hidnplayr 351
 
1249 hidnplayr 352
	; as a Packet has been received, update the TCB timer
1254 hidnplayr 353
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], TCP_SOCKET_TTL
1159 hidnplayr 354
 
1249 hidnplayr 355
	; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
356
	test	[edx + TCP_Packet.Flags], TH_ACK
357
	jz	.call_handler					; No ACK, so no data yet
1159 hidnplayr 358
 
1254 hidnplayr 359
;        mov     eax, [edx + TCP_Packet.SequenceNumber]          ; Calculate sequencenumber in eax
360
;        bswap   eax                                             ;
361
;        add     eax, ecx                                        ;
1159 hidnplayr 362
 
1254 hidnplayr 363
	mov	eax, [edx + TCP_Packet.AckNumber]
1256 clevermous 364
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], eax
1254 hidnplayr 365
	;---------
366
 
1249 hidnplayr 367
	cmp	[TCP_OUT_QUEUE], 0
368
	je	.call_handler
1254 hidnplayr 369
	push	ecx
1159 hidnplayr 370
 
1254 hidnplayr 371
       DEBUGF 1,"Removing all queued packets with smaller ACK\n"
372
 
1249 hidnplayr 373
	mov	ecx, TCP_QUEUE_SIZE
374
	mov	esi, TCP_OUT_QUEUE+4
1159 hidnplayr 375
 
1249 hidnplayr 376
  .loop:
377
	cmp	[esi + tcp_out_queue_entry.data_ptr], 0
1254 hidnplayr 378
	je	.maybe_next
379
	cmp	[esi + tcp_out_queue_entry.seq_num], eax
1249 hidnplayr 380
	jg	.maybe_next
1254 hidnplayr 381
	; TODO: check if the packets belong to the same tcp connection !
1159 hidnplayr 382
 
1254 hidnplayr 383
       DEBUGF 1,"Removing a queued packet\n"
384
 
1249 hidnplayr 385
	push	[esi + tcp_out_queue_entry.data_ptr]
386
	mov	[esi + tcp_out_queue_entry.data_ptr], 0
387
	dec	[TCP_OUT_QUEUE]
388
	call	kernel_free
1159 hidnplayr 389
 
1249 hidnplayr 390
  .maybe_next:
391
	add	esi, tcp_out_queue_entry.size
392
	loop	.loop
1254 hidnplayr 393
 
1249 hidnplayr 394
	pop	ecx
395
  .call_handler:
396
	; Call handler for given TCB state
1254 hidnplayr 397
	mov	eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
398
	DEBUGF 1,"Socket state: %u\n", eax
399
 
1249 hidnplayr 400
	cmp	eax, TCB_LISTEN
1254 hidnplayr 401
	jb	.dump
1249 hidnplayr 402
	cmp	eax, TCB_CLOSED
1254 hidnplayr 403
	ja	.dump
1159 hidnplayr 404
 
1254 hidnplayr 405
	dec	eax
1249 hidnplayr 406
	shl	eax, 2
1254 hidnplayr 407
	add	eax, stateHandler
1159 hidnplayr 408
 
1254 hidnplayr 409
	call	dword[eax]
1159 hidnplayr 410
 
1249 hidnplayr 411
  .dump:
412
	DEBUGF 1,"Dumping TCP packet\n"
1196 hidnplayr 413
	call	kernel_free
414
	add	esp, 4 ; pop (balance stack)
1159 hidnplayr 415
 
1249 hidnplayr 416
	ret
1196 hidnplayr 417
 
418
 
419
 
420
;-----------------------------------------------------------------
421
;
1249 hidnplayr 422
; TCP_socket_send
1196 hidnplayr 423
;
1249 hidnplayr 424
; IN: eax = socket pointer
425
;     ecx = number of bytes to send
426
;     esi = pointer to data
427
;
1196 hidnplayr 428
;-----------------------------------------------------------------
1249 hidnplayr 429
align 4
430
TCP_socket_send:
1196 hidnplayr 431
 
1249 hidnplayr 432
	DEBUGF 1,"Creating TCP Packet\n"
1159 hidnplayr 433
 
1249 hidnplayr 434
	mov	di , IP_PROTO_TCP
1159 hidnplayr 435
 
1249 hidnplayr 436
; Create an IPv4 Packet of the correct size
437
	push	eax
438
	mov	ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
439
	mov	eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
1159 hidnplayr 440
 
1249 hidnplayr 441
; meanwhile, create the pseudoheader in stack,
442
; (now that we still have all the variables that are needed.)
443
	push	cx
444
	push	di
1159 hidnplayr 445
	push	eax
1249 hidnplayr 446
	push	ebx
1159 hidnplayr 447
 
448
 
1249 hidnplayr 449
	push	ecx esi eax		; save some variables for later
1254 hidnplayr 450
	add	ecx, TCP_Packet.Options
1249 hidnplayr 451
	call	IPv4_create_packet
452
	cmp	edi, -1
453
	je	.fail
1159 hidnplayr 454
 
1249 hidnplayr 455
	pop	esi
1159 hidnplayr 456
 
1249 hidnplayr 457
; Now add the TCP header to the IPv4 packet
1159 hidnplayr 458
 
1249 hidnplayr 459
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
460
	pop	[edi + TCP_Packet.SequenceNumber]
1159 hidnplayr 461
 
1249 hidnplayr 462
	push	dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
463
	pop	dword [edi + TCP_Packet.SourcePort]
1159 hidnplayr 464
 
465
 
1249 hidnplayr 466
	push	[esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
467
	pop	[edi + TCP_Packet.AckNumber]
1159 hidnplayr 468
 
1249 hidnplayr 469
	mov	al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
470
	mov	[edi + TCP_Packet.Flags], al
1159 hidnplayr 471
 
1254 hidnplayr 472
	mov	[edi + TCP_Packet.Window], 0x0005	   ; 1280 bytes
1249 hidnplayr 473
	mov	[edi + TCP_Packet.UrgentPointer], 0
474
	mov	[edi + TCP_Packet.DataOffset], 0x50
475
	mov	[edi + TCP_Packet.Checksum], 0
1159 hidnplayr 476
 
1249 hidnplayr 477
; Copy the data
478
	mov	esi, [esp]
479
	mov	ecx, [esp+4]
1254 hidnplayr 480
	add	edi, TCP_Packet.Options
1159 hidnplayr 481
 
1249 hidnplayr 482
	shr	ecx, 1
483
	jnc	.nb
484
	movsb
485
.nb:	shr	ecx, 1
486
	jnc	.nw
487
	movsw
488
.nw:	rep movsd
1159 hidnplayr 489
 
1249 hidnplayr 490
; Now, calculate the checksum for pseudoheader
491
	xor	edx, edx
492
	mov	ecx, 12
493
	mov	esi, esp
494
	call	checksum_1
495
	add	esp, 12 				   ; remove the pseudoheader from stack
496
; And that of the data
497
	pop	esi
498
	pop	ecx
499
	call	checksum_1
500
; Now create the final checksum and store it in TCP header
501
	call	checksum_2
502
	mov	[edi + TCP_Packet.Checksum], dx
1159 hidnplayr 503
 
1249 hidnplayr 504
; And now, send it!
505
	DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
1254 hidnplayr 506
	lea	esi, [ebx+ETH_DEVICE.transmit]
1249 hidnplayr 507
	mov	edx, [edi + TCP_Packet.AckNumber]
508
	jmp	TCP_add_to_queue
1159 hidnplayr 509
 
1249 hidnplayr 510
  .fail:
1254 hidnplayr 511
	add	esp, 12+12+4
1159 hidnplayr 512
	ret
513
 
514
 
515
 
516
 
517
 
1249 hidnplayr 518
;-----------------------------------------------------------------
1159 hidnplayr 519
;
1249 hidnplayr 520
; TCP_send_ack
1159 hidnplayr 521
;
1249 hidnplayr 522
; IN: eax = socket pointer
523
;      bl = flags
1159 hidnplayr 524
;
1249 hidnplayr 525
;-----------------------------------------------------------------
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
 
1255 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
1257 hidnplayr 572
	pushd	[edi-4] ; destination address  ; TODO: fix this, IPv4 packet could have options..
1254 hidnplayr 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
 
1255 hidnplayr 601
;---------- TCB state handlers start here
602
 
603
 
604
 
605
 
1249 hidnplayr 606
align 4
607
stateTCB_LISTEN:
1254 hidnplayr 608
 
609
	DEBUGF	1,"TCBStateHandler: Listen\n"
610
 
1159 hidnplayr 611
	; In this case, we are expecting a SYN Packet
612
	; For now, if the Packet is a SYN, process it, and send a response
613
	; If not, ignore it
614
 
615
	; Look at control flags
1249 hidnplayr 616
	test	[edx + TCP_Packet.Flags], TH_SYN
1159 hidnplayr 617
	jz	.exit
1256 clevermous 618
	; Exit if backlog queue is full
619
	mov	ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
620
	cmp	ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
621
	jae	.exit
622
	; Allocate new socket
623
	push	esi
624
	call	net_socket_alloc
625
	pop	esi
626
	test	eax, eax
627
	jz	.exit
628
	; Copy structure from current socket to new, including lock
629
	push	esi edi
630
	lea	esi, [ebx + SOCKET_head.PID]	; yes, PID must also be copied
631
	lea	edi, [eax + SOCKET_head.PID]
632
	mov	ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4
633
	rep	movsd
634
	pop	edi esi
635
	; Push pointer to new socket to queue
636
	movzx	ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
637
	inc	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
638
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax
1159 hidnplayr 639
 
640
	; We have a SYN. update the socket with this IP Packets details,
641
	; And send a response
642
 
1256 clevermous 643
	mov	[eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
644
	mov	cx, [edx + TCP_Packet.SourcePort]
645
	mov	[eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx
646
	mov	ecx, [edx + TCP_Packet.SequenceNumber]
647
	mov	[eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx
648
	mov	[eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx
649
	lea	esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
1249 hidnplayr 650
	inc_INET esi ; RCV.NXT
1256 clevermous 651
	mov	ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
652
	mov	[eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx
1159 hidnplayr 653
 
1256 clevermous 654
	mov	[eax + SOCKET_head.lock], 0
1254 hidnplayr 655
	mov	[ebx + SOCKET_head.lock], 0
656
 
1256 clevermous 657
	push	eax
1249 hidnplayr 658
	; Now construct the response
1159 hidnplayr 659
	mov	bl, TH_SYN + TH_ACK
1249 hidnplayr 660
	call	TCP_send_ack
1256 clevermous 661
	pop	eax
1159 hidnplayr 662
 
1256 clevermous 663
	mov	[eax +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
664
	call	notify_network_event
1159 hidnplayr 665
 
666
	; increment SND.NXT in socket
1256 clevermous 667
	lea	esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
1249 hidnplayr 668
	inc_INET esi
1256 clevermous 669
	ret
1159 hidnplayr 670
 
671
  .exit:
1254 hidnplayr 672
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 673
	ret
674
 
675
 
1249 hidnplayr 676
align 4
677
stateTCB_SYN_SENT:
1254 hidnplayr 678
 
679
	DEBUGF	1,"TCBStateHandler: Syn_Sent\n"
680
 
1159 hidnplayr 681
	; We are awaiting an ACK to our SYN, with a SYM
682
	; Look at control flags - expecting an ACK
683
 
1249 hidnplayr 684
	mov	al, [edx + TCP_Packet.Flags]
1159 hidnplayr 685
	and	al, TH_SYN + TH_ACK
686
	cmp	al, TH_SYN + TH_ACK
687
	je	.syn_ack
688
 
689
	test	al, TH_SYN
690
	jz	.exit
691
 
1254 hidnplayr 692
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
693
	pushd	TH_SYN + TH_ACK
1159 hidnplayr 694
	jmp	.send
695
 
696
  .syn_ack:
1254 hidnplayr 697
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
698
	pushd	TH_ACK
1159 hidnplayr 699
 
700
  .send:
701
	; Store the recv.nxt field
1249 hidnplayr 702
	mov	eax, [edx + TCP_Packet.SequenceNumber]
1254 hidnplayr 703
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
704
	bswap	eax
705
	inc	eax
706
	bswap	eax
707
	mov	[ebx +	SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax	      ; Update our recv.nxt field
708
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 709
 
1255 hidnplayr 710
	lea	esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
711
	inc_INET esi
712
 
1159 hidnplayr 713
	; Send an ACK
1254 hidnplayr 714
	mov	eax, ebx
1159 hidnplayr 715
	pop	ebx
1249 hidnplayr 716
	call	TCP_send_ack
1159 hidnplayr 717
 
718
  .exit:
1254 hidnplayr 719
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 720
	ret
721
 
722
 
1249 hidnplayr 723
 
724
align 4
725
stateTCB_SYN_RECEIVED:
1254 hidnplayr 726
 
727
	DEBUGF	1,"TCBStateHandler: Syn_received\n"
728
 
1159 hidnplayr 729
	; In this case, we are expecting an ACK Packet
730
	; For now, if the Packet is an ACK, process it,
731
	; If not, ignore it
732
 
1249 hidnplayr 733
	test	[edx + TCP_Packet.Flags], TH_RST
1159 hidnplayr 734
	jz	.check_ack
735
 
1254 hidnplayr 736
  ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
737
 ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
738
  ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
739
 ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
1159 hidnplayr 740
 
1254 hidnplayr 741
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
1159 hidnplayr 742
	jmp	.exit
743
 
744
  .check_ack:
745
	; Look at control flags - expecting an ACK
1249 hidnplayr 746
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 747
	jz	.exit
748
 
1254 hidnplayr 749
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
1256 clevermous 750
	mov	eax, ebx
751
	call	notify_network_event
1159 hidnplayr 752
 
753
  .exit:
1254 hidnplayr 754
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 755
	ret
756
 
757
 
1249 hidnplayr 758
 
759
align 4
760
stateTCB_ESTABLISHED:
1254 hidnplayr 761
 
762
 
763
	DEBUGF	1,"TCBStateHandler: Established\n"
764
 
1255 hidnplayr 765
	mov	eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
766
	cmp	eax, [edx + TCP_Packet.SequenceNumber]
767
	jne	.exit
768
 
1159 hidnplayr 769
	; Here we are expecting data, or a request to close
770
	; OR both...
771
 
772
	; Did we receive a FIN or RST?
1249 hidnplayr 773
	test	[edx + TCP_Packet.Flags], TH_FIN
1159 hidnplayr 774
	jz	.check_ack
775
 
776
	; It was a fin or reset.
777
 
1254 hidnplayr 778
;;; TODO: write following code:
1159 hidnplayr 779
	; Remove resend entries from the queue  - I dont want to send any more data
1249 hidnplayr 780
	; Send an ACK to that fin, and enter closewait state
1159 hidnplayr 781
 
782
  .check_ack:
783
	; Check that we received an ACK
1249 hidnplayr 784
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 785
	jz	.exit
786
 
1254 hidnplayr 787
	DEBUGF	1,"Received ACK\n"
788
 
1159 hidnplayr 789
	; First, look at the incoming window. If this is less than or equal to 1024,
790
	; Set the socket window timer to 1. This will stop an additional Packets being queued.
791
	; ** I may need to tweak this value, since I do not know how many Packets are already queued
1255 hidnplayr 792
	push	ecx
1249 hidnplayr 793
	mov	cx, [edx + TCP_Packet.Window]
1159 hidnplayr 794
	xchg	cl, ch
795
	cmp	cx, 1024
796
	ja	@f
1249 hidnplayr 797
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
1255 hidnplayr 798
      @@:
799
	pop	ecx
1159 hidnplayr 800
 
1255 hidnplayr 801
	test	ecx, ecx
802
	jnz	.data			   ; Read data, if any
1159 hidnplayr 803
 
1255 hidnplayr 804
	lea	esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
805
	inc_INET esi
1159 hidnplayr 806
 
807
	; If we had received a fin, we need to ACK it.
1254 hidnplayr 808
	cmp	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
1159 hidnplayr 809
	je	.ack
810
	jmp	.exit
811
 
812
  .data:
1255 hidnplayr 813
	     ;;;
814
	lea	esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
815
	add_INET esi
816
 
1254 hidnplayr 817
	DEBUGF	1,"Got data!\n"
1249 hidnplayr 818
	mov	esi, [esp + 4]
819
	sub	edx, esi
820
	mov	edi, edx
1255 hidnplayr 821
	mov	eax, ebx
1249 hidnplayr 822
	call	socket_internal_receiver
1159 hidnplayr 823
 
824
  .ack:
1254 hidnplayr 825
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 826
	; Send an ACK
1254 hidnplayr 827
	mov	eax, ebx
1159 hidnplayr 828
	mov	bl, TH_ACK
1249 hidnplayr 829
	call	TCP_send_ack
1159 hidnplayr 830
  .exit:
1254 hidnplayr 831
 
832
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 833
	ret
834
 
835
 
1249 hidnplayr 836
 
837
align 4
838
stateTCB_FIN_WAIT_1:
1254 hidnplayr 839
 
840
	DEBUGF	1,"TCBStateHandler: Fin_wait_1\n"
841
 
1159 hidnplayr 842
	; We can either receive an ACK of a fin, or a fin
1249 hidnplayr 843
	mov	al, [edx + TCP_Packet.Flags]
1159 hidnplayr 844
	and	al, TH_FIN + TH_ACK
845
 
846
	cmp	al, TH_ACK
847
	jne	@f
848
 
849
	; It was an ACK
1254 hidnplayr 850
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
1159 hidnplayr 851
	jmp	.exit
852
 
1254 hidnplayr 853
    @@: mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
1159 hidnplayr 854
	cmp	al, TH_FIN
855
	je	@f
1254 hidnplayr 856
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 857
 
1249 hidnplayr 858
    @@: lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
859
	inc_INET esi
1254 hidnplayr 860
 
861
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 862
	; Send an ACK
1254 hidnplayr 863
	mov	eax, ebx
1159 hidnplayr 864
	mov	bl, TH_ACK
1249 hidnplayr 865
	call	TCP_send_ack
1159 hidnplayr 866
 
867
  .exit:
1254 hidnplayr 868
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 869
	ret
870
 
871
 
1249 hidnplayr 872
 
873
align 4
874
stateTCB_FIN_WAIT_2:
1254 hidnplayr 875
 
876
	DEBUGF	1,"TCBStateHandler: Fin_wait_2\n"
877
 
1249 hidnplayr 878
	test	[edx + TCP_Packet.Flags], TH_FIN
1159 hidnplayr 879
	jz	.exit
880
 
881
	; Change state, as we have a fin
1254 hidnplayr 882
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 883
 
1249 hidnplayr 884
	lea	esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
885
	inc_INET esi
1159 hidnplayr 886
 
1254 hidnplayr 887
	mov	[ebx + SOCKET_head.lock], 0
888
 
1159 hidnplayr 889
	; Send an ACK
1254 hidnplayr 890
	mov	eax, ebx
1159 hidnplayr 891
	mov	bl, TH_ACK
1249 hidnplayr 892
	call	TCP_send_ack
1159 hidnplayr 893
 
894
  .exit:
1254 hidnplayr 895
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 896
	ret
897
 
898
 
1249 hidnplayr 899
 
900
align 4
901
stateTCB_CLOSE_WAIT:
1254 hidnplayr 902
 
903
	DEBUGF	1,"TCBStateHandler: close_wait\n"
1159 hidnplayr 904
	; Intentionally left empty
905
	; socket_close_tcp handles this
1254 hidnplayr 906
 
907
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 908
	ret
909
 
910
 
1249 hidnplayr 911
 
912
align 4
913
stateTCB_CLOSING:
1254 hidnplayr 914
 
915
	DEBUGF	1,"TCBStateHandler: closingn\n"
916
 
1159 hidnplayr 917
	; We can either receive an ACK of a fin, or a fin
1249 hidnplayr 918
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 919
	jz	.exit
920
 
1254 hidnplayr 921
	mov	[ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
1159 hidnplayr 922
 
923
  .exit:
1254 hidnplayr 924
 
925
	mov	[ebx + SOCKET_head.lock], 0
1159 hidnplayr 926
	ret
927
 
928
 
1249 hidnplayr 929
align 4
930
stateTCB_LAST_ACK:
1254 hidnplayr 931
 
932
	DEBUGF	1,"TCBStateHandler: last_ackn\n"
933
 
1159 hidnplayr 934
	; Look at control flags - expecting an ACK
1249 hidnplayr 935
	test	[edx + TCP_Packet.Flags], TH_ACK
1159 hidnplayr 936
	jz	.exit
937
 
1254 hidnplayr 938
	mov	[ebx + SOCKET_head.lock], 0
939
 
1159 hidnplayr 940
	; delete the socket
941
	stdcall net_socket_free, ebx
942
 
943
  .exit:
944
	ret
945
 
946
 
1249 hidnplayr 947
align 4
948
stateTCB_TIME_WAIT:
1254 hidnplayr 949
 
950
	DEBUGF	1,"TCBStateHandler: time_wait\n"
951
 
952
	mov	[ebx + SOCKET_head.lock], 0
953
 
1159 hidnplayr 954
	ret
955
 
956
 
1249 hidnplayr 957
align 4
958
stateTCB_CLOSED:
1254 hidnplayr 959
 
960
	DEBUGF	1,"TCBStateHandler: closed\n"
961
 
962
	mov	[ebx + SOCKET_head.lock], 0
963
 
1159 hidnplayr 964
	ret
965
 
966
 
967
 
1254 hidnplayr 968
;---------------------------------------------------------------------------
969
;
970
; TCP_API
971
;
972
; This function is called by system function 75
973
;
974
; IN:  subfunction number in bl
975
;      device number in bh
976
;      ecx, edx, .. depends on subfunction
977
;
978
; OUT:
979
;
980
;---------------------------------------------------------------------------
981
align 4
982
TCP_API:
983
 
984
	movzx	eax, bh
985
	shl	eax, 2
986
 
987
	test	bl, bl
988
	jz	.packets_tx	; 0
989
	dec	bl
990
	jz	.packets_rx	; 1
991
 
992
.error:
993
	mov	eax, -1
994
	ret
995
 
996
.packets_tx:
997
	add	eax, TCP_PACKETS_TX
998
	mov	eax, [eax]
999
	ret
1000
 
1001
.packets_rx:
1002
	add	eax, TCP_PACKETS_RX
1003
	mov	eax, [eax]
1004
	ret