Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1159 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;  TCP.INC                                                     ;;
7
;;                                                              ;;
8
;;  TCP Processes for Menuet OS  TCP/IP stack                   ;;
9
;;                                                              ;;
10
;;  Copyright 2002 Mike Hibbett, mikeh@oceanfree.net            ;;
11
;;                                                              ;;
12
;;  See file COPYING for details                                ;;
13
;;  v0.6 : Added reset handling in the established state        ;;
14
;;         Added a timer per socket to allow delays when        ;;
15
;;         rx window gets below 1KB                             ;;
16
;;                                                              ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
 
19
$Revision: 1019 $
20
 
21
 
22
; TCP TCB states
23
TCB_LISTEN		equ 1
24
TCB_SYN_SENT		equ 2
25
TCB_SYN_RECEIVED	equ 3
26
TCB_ESTABLISHED 	equ 4
27
TCB_FIN_WAIT_1		equ 5
28
TCB_FIN_WAIT_2		equ 6
29
TCB_CLOSE_WAIT		equ 7
30
TCB_CLOSING		equ 8
31
TCB_LAST_ACK		equ 9
32
TCB_TIMED_WAIT		equ 10
33
TCB_CLOSED		equ 11
34
 
35
TH_FIN			equ 0x01
36
TH_SYN			equ 0x02
37
TH_RST			equ 0x04
38
TH_PUSH 		equ 0x08
39
TH_ACK			equ 0x10
40
TH_URG			equ 0x20
41
 
42
TWOMSL			equ 10	    ; # of secs to wait before closing socket
43
 
44
TCP_RETRIES		equ 5		    ; Number of times to resend a Packet
45
TCP_TIMEOUT		equ 10		    ; resend if not replied to in x hs
46
 
47
struct	TCP_Packet
48
	.SourcePort		dw ?
49
	.DestinationPort	dw ?
50
	.SequenceNumber 	dd ?
51
	.AckNumber		dd ?
52
	.DataOffset		db ?  ; DataOffset[0-3 bits] and Reserved[4-7]
53
	.Flags			db ?  ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
54
	.Window 		dw ?
55
	.Checksum		dw ?
56
	.UrgentPointer		dw ?
57
	.Options		rb 3
58
	.Padding		db ?
59
	.Data:
60
ends
61
 
62
 
63
;***************************************************************************
64
;   Function
65
;      tcp_tcb_handler
66
;
67
;   Description
68
;       Handles sockets in the timewait state, closing them
69
;       when the TCB timer expires
70
;
71
;***************************************************************************
72
 
73
tcp_tcb_handler:
74
	; scan through all the sockets, decrementing active timers
75
 
76
	mov	ebx, net_sockets
77
 
78
	cmp	[ebx + SOCKET.NextPtr], 0
79
	je	.exit
80
	DEBUGF	1, "K : sockets:\n"
81
 
82
  .next_socket:
83
	mov	ebx, [ebx + SOCKET.NextPtr]
84
	or	ebx, ebx
85
	jz	.exit
86
 
87
	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.TCBState]
88
 
89
	cmp	[ebx + SOCKET.TCBTimer], 0
90
	jne	.decrement_tcb
91
	cmp	[ebx + SOCKET.wndsizeTimer], 0
92
	jne	.decrement_wnd
93
	jmp	.next_socket
94
 
95
  .decrement_tcb:
96
	; decrement it, delete socket if TCB timer = 0 & socket in timewait state
97
	dec	[ebx + SOCKET.TCBTimer]
98
	jnz	.next_socket
99
 
100
	cmp	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
101
	jne	.next_socket
102
 
103
	push	[ebx + SOCKET.PrevPtr]
104
	stdcall net_socket_free, ebx
105
	pop	ebx
106
	jmp	.next_socket
107
 
108
  .decrement_wnd:
109
	; TODO - prove it works!
110
	dec	[ebx + SOCKET.wndsizeTimer]
111
	jmp	.next_socket
112
 
113
  .exit:
114
	ret
115
 
116
 
117
;***************************************************************************
118
;   Function
119
;      tcp_tx_handler
120
;
121
;   Description
122
;       Handles queued TCP data
123
;       This is a kernel function, called by stack_handler
124
;
125
;***************************************************************************
126
 
127
proc tcp_tx_handler stdcall
128
    ; decrement all resend buffers timers. If they
129
    ; expire, queue them for sending, and restart the timer.
130
    ; If the retries counter reach 0, delete the entry
131
 
132
	mov	esi, resendQ
133
	mov	ecx, 0
134
 
135
  .next_resendq:
136
	cmp	ecx, NUMRESENDENTRIES
137
	je	.exit		    ; None left
138
	cmp	dword[esi + 4], 0
139
	jne	@f		     ; found one
140
	inc	ecx
141
	add	esi, 8
142
	jmp	.next_resendq
143
 
144
    @@: ; we have one. decrement it's timer by 1
145
	dec	word[esi + 2]
146
	jz	@f
147
	inc	ecx
148
	add	esi, 8
149
	jmp	.next_resendq	    ; Timer not zero, so move on
150
 
151
    @@:
152
	xor	ebx, ebx
153
	; restart timer, and decrement retries
154
	; After the first resend, back of on next, by a factor of 5
155
	mov	[esi + 2], word TCP_TIMEOUT * 5
156
	dec	byte[esi + 1]
157
	jnz	@f
158
 
159
	; retries now 0, so delete from queue
160
	xchg	 [esi + 4], ebx
161
 
162
    @@: ; resend Packet
163
	pushad
164
 
165
	mov	eax, EMPTY_QUEUE
166
	call	dequeue
167
	cmp	ax, NO_BUFFER
168
	jne	.tth004z
169
 
170
	; TODO - try again in 10ms.
171
	test	ebx, ebx
172
	jnz	@f
173
	mov	[esi + 4], ebx
174
 
175
    @@: ; Mark it to expire in 10ms - 1 tick
176
	mov	byte[esi + 1], 1
177
	mov	word[esi + 2], 1
178
	jmp	.tth005
179
 
180
  .tth004z:
181
	; we have a buffer # in ax
182
	push	eax ecx
183
	mov	ecx, IPBUFFSIZE
184
	mul	ecx
185
	add	eax, IPbuffs
186
 
187
	; we have the buffer address in eax
188
	mov	edi, eax
189
	pop	ecx
190
	; Now get buffer location, and copy buffer across. argh! more copying,,
191
	mov	esi, resendBuffer
192
    @@: add	esi, IPBUFFSIZE
193
	loop	@b
194
 
195
	; we have resend buffer location in esi
196
	mov	ecx, IPBUFFSIZE
197
 
198
	; copy data across
199
	push	edi
200
	cld
201
	rep	movsb
202
	pop	edi
203
 
204
	; queue Packet
205
	mov	eax, NET1OUT_QUEUE
206
	mov	edx, [IP_LIST]
207
	cmp	edx, [edi + IP_Packet.DestinationAddress]
208
	jne	.not_local
209
	mov	eax, IPIN_QUEUE
210
 
211
  .not_local:
212
	pop	ebx
213
	call	queue
214
 
215
  .tth005:
216
	popad
217
 
218
	inc	ecx
219
	add	esi, 8
220
	jmp	.next_resendq
221
 
222
  .exit:
223
	ret
224
endp
225
 
226
 
227
;***************************************************************************
228
;   Function
229
;      tcp_rx
230
;
231
;   Description
232
;       TCP protocol handler
233
;       This is a kernel function, called by ip_rx
234
;       IP buffer address given in edx
235
;          IP buffer number in eax
236
;          Free up (or re-use) IP buffer when finished
237
;
238
;***************************************************************************
239
 
240
proc tcp_rx stdcall uses ebx
241
	; The process is as follows.
242
	; Look for a socket with matching remote IP, remote port, local port
243
	; if not found, then
244
	; look for remote IP + local port match ( where sockets remote port = 0)
245
	; if not found, then
246
	; look for a socket where local socket port == IP Packets remote port
247
	; where sockets remote port, remote IP = 0
248
	; discard if not found
249
	; Call sockets tcbStateMachine, with pointer to Packet.
250
	; the state machine will not delete the Packet, so do that here.
251
 
252
	push	eax
253
 
254
	; Look for a socket where
255
	; IP Packet TCP Destination Port = local Port
256
	; IP Packet SA = Remote IP
257
	; IP Packet TCP Source Port = remote Port
258
 
259
	mov	ebx, net_sockets
260
 
261
  .next_socket.1:
262
	mov	ebx, [ebx + SOCKET.NextPtr]
263
	or	ebx, ebx
264
	jz	.next_socket.1.exit
265
 
266
;        DEBUGF  1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
267
 
268
	mov	ax, [edx + 20 + TCP_Packet.DestinationPort]  ; get the dest. port from the TCP hdr
269
	cmp	[ebx + SOCKET.LocalPort], ax		; get the dest. port from the TCP hdr
270
	jne	.next_socket.1				; different - try next socket
271
 
272
;        DEBUGF  1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
273
 
274
	mov	eax, [edx + IP_Packet.SourceAddress]	; get the source IP Addr from the IP hdr
275
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
276
	jne	.next_socket.1				; different - try next socket
277
 
278
;        DEBUGF  1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_Packet.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
279
 
280
	mov	ax, [edx + 20 + TCP_Packet.SourcePort]	; get the source port from the TCP hdr
281
	cmp	[ebx + SOCKET.RemotePort], ax		; compare with socket's remote port
282
	jne	.next_socket.1				; different - try next socket
283
 
284
	; We have a complete match - use this socket
285
	jmp	.change_state
286
 
287
  .next_socket.1.exit:
288
 
289
	; If we got here, there was no match
290
	; Look for a socket where
291
	; IP Packet TCP Destination Port = local Port
292
	; IP Packet SA = Remote IP
293
	; socket remote Port = 0
294
 
295
	mov	ebx, net_sockets
296
 
297
  .next_socket.2:
298
	mov	ebx, [ebx + SOCKET.NextPtr]
299
	or	ebx, ebx
300
	jz	.next_socket.2.exit
301
 
302
;        DEBUGF  1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
303
 
304
	mov	ax, [edx + 20 + TCP_Packet.DestinationPort]  ; get the dest. port from the TCP hdr
305
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
306
	jne	.next_socket.2				; different - try next socket
307
 
308
;        DEBUGF  1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
309
 
310
	mov	eax, [edx + IP_Packet.SourceAddress]	; get the source IP Addr from the IP hdr
311
	cmp	[ebx + SOCKET.RemoteIP], eax		; compare with socket's remote IP
312
	jne	.next_socket.2				; different - try next socket
313
 
314
;        DEBUGF  1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
315
 
316
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
317
	jne	.next_socket.2				; different - try next socket
318
 
319
	; We have a complete match - use this socket
320
	jmp	.change_state
321
 
322
  .next_socket.2.exit:
323
 
324
	; If we got here, there was no match
325
	; Look for a socket where
326
	; IP Packet TCP Destination Port = local Port
327
	; socket Remote IP = 0
328
	; socket remote Port = 0
329
 
330
	mov	ebx, net_sockets
331
 
332
  .next_socket.3:
333
	mov	ebx, [ebx + SOCKET.NextPtr]
334
	or	ebx, ebx
335
	jz	.next_socket.3.exit
336
 
337
;        DEBUGF  1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
338
 
339
	mov	ax, [edx + 20 + TCP_Packet.DestinationPort]  ; get destination port from the TCP hdr
340
	cmp	[ebx + SOCKET.LocalPort], ax		; compare with socket's local port
341
	jne	.next_socket.3				; different - try next socket
342
 
343
;        DEBUGF  1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
344
 
345
	cmp	[ebx + SOCKET.RemoteIP], 0		; only match a socket remote IP of 0
346
	jne	.next_socket.3				; different - try next socket
347
 
348
;        DEBUGF  1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
349
 
350
	cmp	[ebx + SOCKET.RemotePort], 0		; only match a remote socket of 0
351
	jne	.next_socket.3				; different - try next socket
352
 
353
	; We have a complete match - use this socket
354
	jmp	.change_state
355
 
356
  .next_socket.3.exit:
357
 
358
	; If we got here, we need to reject the Packet
359
 
360
	DEBUGF	1, "K : tcp_rx - dumped\n"
361
	DEBUGF	1, "K :   --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [edx + IP_Packet.SourceAddress], [edx + 20 + TCP_Packet.SourcePort]:4, [edx + 20 + TCP_Packet.Flags]:2
362
 
363
	inc	[dumped_rx_count]
364
	jmp	.exit
365
 
366
  .change_state:
367
 
368
	; We have a valid socket/TCB, so call the TCB State Machine for that skt.
369
	; socket is pointed to by ebx
370
	; IP Packet is pointed to by edx
371
	; IP buffer number is on stack ( it will be popped at the end)
372
 
373
	stdcall tcpStateMachine, ebx
374
 
375
  .exit:
376
	pop	eax
377
	call	freeBuff
378
	ret
379
endp
380
 
381
 
382
;***************************************************************************
383
;   Function
384
;      buildTCPPacket
385
;
386
;   Description
387
;       builds an IP Packet with TCP data fully populated for transmission
388
;       You may destroy any and all registers
389
;          TCP control flags specified in bl
390
;          This TCB is in [sktAddr]
391
;          User data pointed to by esi
392
;       Data length in ecx
393
;          Transmit buffer number in eax
394
;
395
;***************************************************************************
396
 
397
proc build_tcp_Packet stdcall, sockAddr:DWORD
398
	push	ecx			   ; Save data length
399
 
400
	; convert buffer pointer eax to the absolute address
401
	mov	ecx, IPBUFFSIZE
402
	mul	ecx
403
	add	eax, IPbuffs
404
 
405
	mov	edx, eax
406
 
407
	mov	[edx + 20 + TCP_Packet.Flags], bl		; TCP flags
408
 
409
	mov	ebx, [sockAddr]
410
 
411
	; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
412
 
413
	; Fill in the IP header ( some data is in the socket descriptor)
414
	mov	eax, [ebx + SOCKET.LocalIP]
415
	mov	[edx + IP_Packet.SourceAddress], eax
416
	mov	eax, [ebx + SOCKET.RemoteIP]
417
	mov	[edx + IP_Packet.DestinationAddress], eax
418
 
419
	mov	[edx + IP_Packet.VersionAndIHL], 0x45
420
	mov	[edx + IP_Packet.TypeOfService], 0
421
 
422
	pop	eax		      ; Get the TCP data length
423
	push	eax
424
 
425
	add	eax, 20 + 20	       ; add IP header and TCP header lengths
426
	rol	ax, 8
427
	mov	[edx + IP_Packet.TotalLength], ax
428
	mov	[edx + IP_Packet.Identification], 0
429
	mov	[edx + IP_Packet.FlagsAndFragmentOffset], 0x0040
430
	mov	[edx + IP_Packet.TimeToLive], 0x20
431
	mov	[edx + IP_Packet.Protocol], PROTOCOL_TCP
432
 
433
	; Checksum left unfilled
434
	mov	[edx + IP_Packet.HeaderChecksum], 0
435
 
436
	; Fill in the TCP header (some data is in the socket descriptor)
437
	mov	ax, [ebx + SOCKET.LocalPort]
438
	mov	[edx + 20 + TCP_Packet.SourcePort], ax		; Local Port
439
 
440
	mov	ax, [ebx + SOCKET.RemotePort]
441
	mov	[edx + 20 + TCP_Packet.DestinationPort], ax	; desitination Port
442
 
443
	; Checksum left unfilled
444
	mov	[edx + 20 + TCP_Packet.Checksum], 0
445
 
446
	; sequence number
447
	mov	eax, [ebx + SOCKET.SND_NXT]
448
	mov	[edx + 20 + TCP_Packet.SequenceNumber], eax
449
 
450
	; ack number
451
	mov	eax, [ebx + SOCKET.RCV_NXT]
452
	mov	[edx + 20 + TCP_Packet.AckNumber], eax
453
 
454
	; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
455
	; 768 bytes seems better
456
	mov	[edx + 20 + TCP_Packet.Window], 0x0003
457
 
458
	; Urgent pointer (0)
459
	mov	[edx + 20 + TCP_Packet.UrgentPointer], 0
460
 
461
	; data offset ( 0x50 )
462
	mov	[edx + 20 + TCP_Packet.DataOffset], 0x50
463
 
464
	pop	ecx		     ; count of bytes to send
465
	mov	ebx, ecx	    ; need the length later
466
 
467
	cmp	ebx, 0
468
	jz	@f
469
 
470
	mov	edi, edx
471
	add	edi, 40
472
	cld
473
	rep	movsb		    ; copy the data across
474
 
475
    @@: ; we have edx as IPbuffer ptr.
476
	; Fill in the TCP checksum
477
	; First, fill in pseudoheader
478
	mov	eax, [edx + IP_Packet.SourceAddress]
479
	mov	[pseudoHeader], eax
480
	mov	eax, [edx + IP_Packet.DestinationAddress]
481
	mov	[pseudoHeader + 4], eax
482
	mov	word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
483
	add	ebx, 20
484
	mov	[pseudoHeader + 10], bh
485
	mov	[pseudoHeader + 11], bl
486
 
487
	mov	eax, pseudoHeader
488
	mov	[checkAdd1], eax
489
	mov	word[checkSize1], 12
490
	mov	eax, edx
491
	add	eax, 20
492
	mov	[checkAdd2], eax
493
	mov	eax, ebx
494
	mov	[checkSize2], ax
495
 
496
	call	checksum
497
 
498
	; store it in the TCP checksum ( in the correct order! )
499
	mov	ax, [checkResult]
500
	rol	ax, 8
501
	mov	[edx + 20 + TCP_Packet.Checksum], ax
502
 
503
	; Fill in the IP header checksum
504
    movzx   eax, byte [edx + IP_Packet.VersionAndIHL]  ; Calculate Header length by using IHL field
505
    and     eax, 0x0000000F  ;
506
    shl     eax, 2	     ;
507
 
508
	stdcall checksum_jb, edx, eax  ; buf_ptr, buf_size
509
	rol	ax, 8
510
	mov	[edx + IP_Packet.HeaderChecksum], ax
511
 
512
	ret
513
endp
514
 
515
 
516
; Increments the 32 bit value pointed to by esi in internet order
517
proc inc_inet_esi stdcall
518
	push	eax
519
	mov	eax, [esi]
520
	bswap	eax
521
	inc	eax
522
	bswap	eax
523
	mov	[esi], eax
524
	pop	eax
525
	ret
526
endp
527
 
528
 
529
; Increments the 32 bit value pointed to by esi in internet order
530
; by the value in ecx
531
proc add_inet_esi stdcall
532
	push	eax
533
	mov	eax, [esi]
534
	bswap	eax
535
	add	eax, ecx
536
	bswap	eax
537
	mov	[esi], eax
538
	pop	eax
539
	ret
540
endp
541
 
542
 
543
iglobal
544
  TCBStateHandler dd \
545
    stateTCB_LISTEN, \
546
    stateTCB_SYN_SENT, \
547
    stateTCB_SYN_RECEIVED, \
548
    stateTCB_ESTABLISHED, \
549
    stateTCB_FIN_WAIT_1, \
550
    stateTCB_FIN_WAIT_2, \
551
    stateTCB_CLOSE_WAIT, \
552
    stateTCB_CLOSING, \
553
    stateTCB_LAST_ACK, \
554
    stateTCB_TIME_WAIT, \
555
    stateTCB_CLOSED
556
endg
557
 
558
 
559
;***************************************************************************
560
;   Function
561
;      tcpStateMachine
562
;
563
;   Description
564
;       TCP state machine
565
;       This is a kernel function, called by tcp_rx
566
;
567
;       IP buffer address given in edx
568
;          Socket/TCB address in ebx
569
;
570
;       The IP buffer will be released by the caller
571
;***************************************************************************
572
 
573
proc tcpStateMachine stdcall, sockAddr:DWORD
574
	; as a Packet has been received, update the TCB timer
575
	mov	[ebx + SOCKET.TCBTimer], TWOMSL
576
 
577
	; If the received Packet has an ACK bit set,
578
	; remove any Packets in the resend queue that this
579
	; received Packet acknowledges
580
	pushad
581
	test	[edx + 20 + TCP_Packet.Flags], TH_ACK
582
	jz	.call_handler					; No ACK, so no data yet
583
 
584
	; get skt number in eax
585
	stdcall net_socket_addr_to_num, ebx
586
 
587
	; The ack number is in [edx + 28], inet format
588
	; skt in eax
589
 
590
	mov	esi, resendQ
591
	xor	ecx, ecx
592
 
593
  .next_resendq:
594
	cmp	ecx, NUMRESENDENTRIES
595
	je	.call_handler	  ; None left
596
	cmp	[esi + 4], eax
597
	je	@f		  ; found one
598
	inc	ecx
599
	add	esi, 8
600
	jmp	.next_resendq
601
 
602
    @@: 		  ; Can we delete this buffer?
603
 
604
			  ; If yes, goto @@. No, goto .next_resendq
605
	; Get Packet data address
606
 
607
	push	ecx
608
	; Now get buffer location, and copy buffer across. argh! more copying,,
609
	imul	edi, ecx, IPBUFFSIZE
610
	add	edi, resendBuffer
611
 
612
	; we have dest buffer location in edi. incoming Packet in edx.
613
	; Get this Packets sequence number
614
	; preserve al, ecx, esi, edx
615
	mov	ecx, [edi + 20 + TCP_Packet.SequenceNumber]
616
	bswap	ecx
617
	movzx	ebx, word[edi + 2]
618
	xchg	bl, bh
619
	sub	ebx, 40
620
	add	ecx, ebx	  ; ecx is now seq# of last byte +1, intel format
621
 
622
	; get recievd ack #, in intel format
623
	mov	ebx, [edx + 20 + TCP_Packet.AckNumber]
624
	bswap	ebx
625
 
626
	cmp	ebx, ecx	; Finally. ecx = rx'ed ack. ebx = last byte in que
627
				; DANGER! need to handle case that we have just
628
				; passed the 2**32, and wrapped round!
629
	pop	ecx
630
	jae	@f		; if rx > old, delete old
631
 
632
	inc	ecx
633
	add	esi, 8
634
	jmp	.next_resendq
635
 
636
    @@: mov	dword[esi + 4], 0
637
	inc	ecx
638
	add	esi, 8
639
	jmp	.next_resendq
640
 
641
  .call_handler:
642
	popad
643
 
644
	; Call handler for given TCB state
645
 
646
	mov	eax, [ebx + SOCKET.TCBState]
647
	cmp	eax, TCB_LISTEN
648
	jb	.exit
649
	cmp	eax, TCB_CLOSED
650
	ja	.exit
651
 
652
	stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
653
 
654
  .exit:
655
	ret
656
endp
657
 
658
 
659
proc stateTCB_LISTEN stdcall, sockAddr:DWORD
660
	; In this case, we are expecting a SYN Packet
661
	; For now, if the Packet is a SYN, process it, and send a response
662
	; If not, ignore it
663
 
664
	; Look at control flags
665
	test	[edx + 20 + TCP_Packet.Flags], TH_SYN
666
	jz	.exit
667
 
668
	; We have a SYN. update the socket with this IP Packets details,
669
	; And send a response
670
 
671
	mov	eax, [edx + IP_Packet.SourceAddress]
672
	mov	[ebx + SOCKET.RemoteIP], eax
673
	mov	ax, [edx + 20 + TCP_Packet.SourcePort]
674
	mov	[ebx + SOCKET.RemotePort], ax
675
	mov	eax, [edx + 20 + TCP_Packet.SequenceNumber]
676
	mov	[ebx + SOCKET.IRS], eax
677
	mov	[ebx + SOCKET.RCV_NXT], eax
678
	lea	esi, [ebx + SOCKET.RCV_NXT]
679
	call	inc_inet_esi ; RCV.NXT
680
	mov	eax, [ebx + SOCKET.ISS]
681
	mov	[ebx + SOCKET.SND_NXT], eax
682
 
683
	; Now construct the response, and queue for sending by IP
684
	mov	eax, EMPTY_QUEUE
685
	call	dequeue
686
	cmp	ax, NO_BUFFER
687
	je	.exit
688
 
689
	push	eax
690
	mov	bl, TH_SYN + TH_ACK
691
	xor	ecx, ecx
692
	xor	esi, esi
693
	stdcall build_tcp_Packet, [sockAddr]
694
 
695
	mov	eax, NET1OUT_QUEUE
696
;;;        mov     edx, [stack_ip]
697
	mov	ecx, [sockAddr]
698
	cmp	edx, [ecx + SOCKET.RemoteIP]
699
	jne	.not_local
700
	mov	eax, IPIN_QUEUE
701
 
702
  .not_local:
703
	; Send it.
704
	pop	ebx
705
	call	queue
706
 
707
	mov	esi, [sockAddr]
708
	mov	[esi + SOCKET.TCBState], TCB_SYN_RECEIVED
709
 
710
	; increment SND.NXT in socket
711
	add	esi, SOCKET.SND_NXT
712
	call	inc_inet_esi
713
 
714
  .exit:
715
	ret
716
endp
717
 
718
 
719
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
720
	; We are awaiting an ACK to our SYN, with a SYM
721
	; Look at control flags - expecting an ACK
722
 
723
	mov	al, [edx + 20 + TCP_Packet.Flags]
724
	and	al, TH_SYN + TH_ACK
725
	cmp	al, TH_SYN + TH_ACK
726
	je	.syn_ack
727
 
728
	test	al, TH_SYN
729
	jz	.exit
730
 
731
	mov	[ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
732
	push	TH_SYN + TH_ACK
733
	jmp	.send
734
 
735
  .syn_ack:
736
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
737
	push	TH_ACK
738
 
739
  .send:
740
	; Store the recv.nxt field
741
	mov	eax, [edx + 20 + TCP_Packet.SequenceNumber]
742
 
743
	; Update our recv.nxt field
744
	mov	[ebx + SOCKET.RCV_NXT], eax
745
	lea	esi, [ebx + SOCKET.RCV_NXT]
746
	call	inc_inet_esi
747
 
748
	; Send an ACK
749
	; Now construct the response, and queue for sending by IP
750
	mov	eax, EMPTY_QUEUE
751
	call	dequeue
752
	cmp	ax, NO_BUFFER
753
	pop	ebx
754
	je	.exit
755
 
756
	push	eax
757
 
758
	xor	ecx, ecx
759
	xor	esi, esi
760
	stdcall build_tcp_Packet, [sockAddr]
761
 
762
	mov	eax, NET1OUT_QUEUE
763
;;;        mov     edx, [stack_ip]
764
	mov	ecx, [sockAddr]
765
	cmp	edx, [ecx + SOCKET.RemoteIP]
766
	jne	.not_local
767
	mov	eax, IPIN_QUEUE
768
 
769
  .not_local:
770
	; Send it.
771
	pop	ebx
772
	call	queue
773
 
774
  .exit:
775
	ret
776
endp
777
 
778
 
779
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
780
	; In this case, we are expecting an ACK Packet
781
	; For now, if the Packet is an ACK, process it,
782
	; If not, ignore it
783
 
784
	test	[edx + 20 + TCP_Packet.Flags], TH_RST
785
	jz	.check_ack
786
 
787
	push	[ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
788
	pop	[ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
789
 
790
	mov	[ebx + SOCKET.TCBState], TCB_LISTEN
791
	jmp	.exit
792
 
793
  .check_ack:
794
	; Look at control flags - expecting an ACK
795
	test	[edx + 20 + TCP_Packet.Flags], TH_ACK
796
	jz	.exit
797
 
798
	mov	[ebx + SOCKET.TCBState], TCB_ESTABLISHED
799
 
800
  .exit:
801
	ret
802
endp
803
 
804
 
805
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
806
	; Here we are expecting data, or a request to close
807
	; OR both...
808
 
809
	; Did we receive a FIN or RST?
810
	test	[edx + 20 + TCP_Packet.Flags], TH_FIN
811
	jz	.check_ack
812
 
813
	; It was a fin or reset.
814
 
815
	; Remove resend entries from the queue  - I dont want to send any more data
816
	pushad
817
 
818
	; get skt #
819
	stdcall net_socket_addr_to_num, ebx
820
 
821
	mov	esi, resendQ
822
	mov	ecx, 0
823
 
824
  .next_resendq:
825
	cmp	ecx, NUMRESENDENTRIES
826
	je	.last_resendq	    ; None left
827
	cmp	[esi + 4], eax
828
	je	@f		    ; found one
829
	inc	ecx
830
	add	esi, 8
831
	jmp	.next_resendq
832
 
833
    @@: mov	dword[esi + 4], 0
834
	inc	ecx
835
	add	esi, 8
836
	jmp	.next_resendq
837
 
838
  .last_resendq:
839
	popad
840
 
841
    @@: ; Send an ACK to that fin, and enter closewait state
842
 
843
	mov	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
844
	lea	esi, [ebx + SOCKET.RCV_NXT]
845
	mov	eax, [esi]		; save original
846
	call	inc_inet_esi
847
	;; jmp    ste_ack - NO, there may be data
848
 
849
  .check_ack:
850
	; Check that we received an ACK
851
	test	[edx + 20 + TCP_Packet.Flags], TH_ACK
852
	jz	.exit
853
 
854
	; TODO - done, I think!
855
	; First, look at the incoming window. If this is less than or equal to 1024,
856
	; Set the socket window timer to 1. This will stop an additional Packets being queued.
857
	; ** I may need to tweak this value, since I do not know how many Packets are already queued
858
	mov	cx, [edx + 20 + TCP_Packet.Window]
859
	xchg	cl, ch
860
	cmp	cx, 1024
861
	ja	@f
862
 
863
	mov	[ebx + SOCKET.wndsizeTimer], 1
864
 
865
    @@: ; OK, here is the deal
866
	; My recv.nct field holds the seq of the expected next rec byte
867
	; if the recevied sequence number is not equal to this, do not
868
	; increment the recv.nxt field, do not copy data - just send a
869
	; repeat ack.
870
 
871
	; recv.nxt is in dword [edx+24], in inet format
872
	; recv seq is in [sktAddr]+56, in inet format
873
	; just do a comparision
874
	mov	ecx, [ebx + SOCKET.RCV_NXT]
875
	cmp	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
876
	jne	@f
877
	mov	ecx, eax
878
 
879
    @@: cmp	ecx, [edx + 20 + TCP_Packet.SequenceNumber]
880
	jne	.ack
881
 
882
 
883
	; Read the data bytes, store in socket buffer
884
	movzx	ecx, [edx + IP_Packet.TotalLength]
885
	xchg	cl, ch
886
	sub	ecx, 40 		   ; Discard 40 bytes of header
887
	ja	.data			   ; Read data, if any
888
 
889
	; If we had received a fin, we need to ACK it.
890
	cmp	[ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
891
	je	.ack
892
	jmp	.exit
893
 
894
  .data:
895
	push	ebx
896
	add	ebx, SOCKET.lock
897
	call	wait_mutex
898
	pop	ebx
899
 
900
	push	ecx
901
	push	[ebx + SOCKET.PID]	; get socket owner PID
902
	mov	eax, [ebx + SOCKET.rxDataCount]
903
	add	eax, ecx
904
	cmp	eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE
905
	ja	.overflow
906
 
907
	mov	[ebx + SOCKET.rxDataCount], eax      ; increment the count of bytes in buffer
908
 
909
	; point to the location to store the data
910
	lea	edi, [ebx + eax + SOCKETHEADERSIZE]
911
	sub	edi, ecx
912
 
913
	add	edx, 40        ; edx now points to the data
914
	mov	esi, edx
915
 
916
	cld
917
	rep	movsb	       ; copy the data across
918
	mov	[ebx + SOCKET.lock], 0	; release mutex
919
 
920
	; flag an event to the application
921
	pop	eax
922
	mov	ecx, 1
923
	mov	esi, TASK_DATA + TASKDATA.pid
924
 
925
  .next_pid:
926
	cmp	[esi], eax
927
	je	.found_pid
928
	inc	ecx
929
	add	esi, 0x20
930
	cmp	ecx, [TASK_COUNT]
931
	jbe	.next_pid
932
 
933
  .found_pid:
934
	shl	ecx, 8
935
	or	[ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
936
 
937
	pop	ecx
938
 
939
	; Update our recv.nxt field
940
	lea	esi, [ebx + SOCKET.RCV_NXT]
941
	call	add_inet_esi
942
 
943
  .ack:
944
	; Send an ACK
945
	; Now construct the response, and queue for sending by IP
946
	mov	eax, EMPTY_QUEUE
947
	call	dequeue
948
	cmp	ax, NO_BUFFER
949
	je	.exit
950
 
951
	push	eax
952
 
953
	mov	bl, TH_ACK
954
	xor	ecx, ecx
955
	xor	esi, esi
956
	stdcall build_tcp_Packet, [sockAddr]
957
 
958
	mov	eax, NET1OUT_QUEUE
959
 
960
;;;        mov     edx, [stack_ip]
961
	mov	ecx, [sockAddr]
962
	cmp	edx, [ecx + SOCKET.RemoteIP]
963
	jne	.not_local
964
	mov	eax, IPIN_QUEUE
965
 
966
  .not_local:
967
	; Send it.
968
	pop	ebx
969
	call	queue
970
 
971
  .exit:
972
	ret
973
  .overflow:
974
	; no place in buffer
975
	; so simply restore stack and exit
976
	pop	eax ecx
977
	mov	[ebx + SOCKET.lock], 0
978
	ret
979
endp
980
 
981
 
982
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
983
	; We can either receive an ACK of a fin, or a fin
984
	mov	al, [edx + 20 + TCP_Packet.Flags]
985
	and	al, TH_FIN + TH_ACK
986
 
987
	cmp	al, TH_ACK
988
	jne	@f
989
 
990
	; It was an ACK
991
	mov	[ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
992
	jmp	.exit
993
 
994
    @@: mov	[ebx + SOCKET.TCBState], TCB_CLOSING
995
	cmp	al, TH_FIN
996
	je	@f
997
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
998
 
999
    @@: lea	esi, [ebx + SOCKET.RCV_NXT]
1000
	call	inc_inet_esi
1001
 
1002
	; Send an ACK
1003
	mov	eax, EMPTY_QUEUE
1004
	call	dequeue
1005
	cmp	ax, NO_BUFFER
1006
	je	.exit
1007
 
1008
	push	eax
1009
 
1010
	mov	bl, TH_ACK
1011
	xor	ecx, ecx
1012
	xor	esi, esi
1013
	stdcall build_tcp_Packet, [sockAddr]
1014
 
1015
	mov	eax, NET1OUT_QUEUE
1016
;;;        mov     edx, [stack_ip]
1017
	mov	ecx, [sockAddr]
1018
	cmp	edx, [ecx + SOCKET.RemoteIP]
1019
	jne	.not_local
1020
	mov	eax, IPIN_QUEUE
1021
 
1022
  .not_local:
1023
	; Send it.
1024
	pop	ebx
1025
	call	queue
1026
 
1027
  .exit:
1028
	ret
1029
endp
1030
 
1031
 
1032
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
1033
	test	[edx + 20 + TCP_Packet.Flags], TH_FIN
1034
	jz	.exit
1035
 
1036
	; Change state, as we have a fin
1037
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1038
 
1039
	lea	esi, [ebx + SOCKET.RCV_NXT]
1040
	call	inc_inet_esi
1041
 
1042
	; Send an ACK
1043
	mov	eax, EMPTY_QUEUE
1044
	call	dequeue
1045
	cmp	ax, NO_BUFFER
1046
	je	.exit
1047
 
1048
	push	eax
1049
 
1050
	mov	bl, TH_ACK
1051
	xor	ecx, ecx
1052
	xor	esi, esi
1053
	stdcall build_tcp_Packet, [sockAddr]
1054
 
1055
	mov	eax, NET1OUT_QUEUE
1056
;;;        mov     edx, [stack_ip]
1057
	mov	ecx, [sockAddr]
1058
	cmp	edx, [ecx + SOCKET.RemoteIP]
1059
	jne	.not_local
1060
	mov	eax, IPIN_QUEUE
1061
 
1062
  .not_local:
1063
	; Send it.
1064
	pop	ebx
1065
	call	queue
1066
 
1067
  .exit:
1068
	ret
1069
endp
1070
 
1071
 
1072
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
1073
	; Intentionally left empty
1074
	; socket_close_tcp handles this
1075
	ret
1076
endp
1077
 
1078
 
1079
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
1080
	; We can either receive an ACK of a fin, or a fin
1081
	test	[edx + 20 + TCP_Packet.Flags], TH_ACK
1082
	jz	.exit
1083
 
1084
	mov	[ebx + SOCKET.TCBState], TCB_TIMED_WAIT
1085
 
1086
  .exit:
1087
	ret
1088
endp
1089
 
1090
 
1091
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
1092
	; Look at control flags - expecting an ACK
1093
	test	[edx + 20 + TCP_Packet.Flags], TH_ACK
1094
	jz	.exit
1095
 
1096
	; delete the socket
1097
	stdcall net_socket_free, ebx
1098
 
1099
  .exit:
1100
	ret
1101
endp
1102
 
1103
 
1104
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
1105
	ret
1106
endp
1107
 
1108
 
1109
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
1110
	ret
1111
endp
1112
 
1113
 
1114
 
1115
;; [53.7] Send data through STREAM socket
1116
;
1117
; @param EBX is socket number
1118
; @param ECX is application data size (number of bytes to send)
1119
; @param EDX is pointer to application data buffer
1120
; @return 0 (sent successfully) or -1 (error) in EAX
1121
;;
1122
proc socket_write_tcp stdcall
1123
local sockAddr dd ?
1124
 
1125
;        DEBUGF  1, "socket_write_tcp(0x%x)\n", ebx
1126
	stdcall net_socket_num_to_addr, ebx
1127
	or	eax, eax
1128
	jz	.error
1129
 
1130
	mov	ebx, eax
1131
	mov	[sockAddr], ebx
1132
 
1133
	; If the sockets window timer is nonzero, do not queue Packet
1134
	cmp	[ebx + SOCKET.wndsizeTimer], 0
1135
	jne	.error
1136
 
1137
	mov	eax, EMPTY_QUEUE
1138
	call	dequeue
1139
	cmp	ax, NO_BUFFER
1140
	je	.error
1141
 
1142
	push	eax
1143
 
1144
	; Get the address of the callers data
1145
	mov	edi, [TASK_BASE]
1146
	add	edi, TASKDATA.mem_start
1147
	add	edx, [edi]
1148
	mov	esi, edx
1149
 
1150
	pop	eax
1151
	push	eax
1152
 
1153
	push	ecx
1154
	mov	bl, TH_ACK
1155
	stdcall build_tcp_Packet, [sockAddr]
1156
	pop	ecx
1157
 
1158
	; Check destination IP address.
1159
	; If it is the local host IP, route it back to IP_RX
1160
 
1161
	pop	ebx
1162
	push	ecx
1163
 
1164
	mov	eax, NET1OUT_QUEUE
1165
;;; TODO: get device id in edx
1166
	xor	edx, edx
1167
 
1168
	shl	edx, 2
1169
	mov	edx, [IP_LIST+edx]
1170
	mov	ecx, [sockAddr]
1171
	cmp	edx, [ecx + SOCKET.RemoteIP]
1172
	jne	.not_local
1173
	mov	eax, IPIN_QUEUE
1174
 
1175
  .not_local:
1176
	pop	ecx
1177
	push	ebx		    ; save ipbuffer number
1178
 
1179
	call	queue
1180
 
1181
	mov	esi, [sockAddr]
1182
 
1183
	; increament SND.NXT in socket
1184
	; Amount to increment by is in ecx
1185
	add	esi, SOCKET.SND_NXT
1186
	call	add_inet_esi
1187
 
1188
	pop	ebx
1189
 
1190
	; Copy the IP buffer to a resend queue
1191
	; If there isn't one, dont worry about it for now
1192
	mov	esi, resendQ
1193
	mov	ecx, 0
1194
 
1195
  .next_resendq:
1196
	cmp	ecx, NUMRESENDENTRIES
1197
	je	.exit		   ; None found
1198
	cmp	dword[esi + 4], 0
1199
	je	@f		   ; found one
1200
	inc	ecx
1201
	add	esi, 8
1202
	jmp	.next_resendq
1203
 
1204
    @@: push	ebx
1205
 
1206
	; OK, we have a buffer descriptor ptr in esi.
1207
	; resend entry # in ecx
1208
	;  Populate it
1209
	;  socket #
1210
	;  retries count
1211
	;  retry time
1212
	;  fill IP buffer associated with this descriptor
1213
 
1214
	stdcall net_socket_addr_to_num, [sockAddr]
1215
	mov	[esi + 4], eax
1216
	mov	byte[esi + 1], TCP_RETRIES
1217
	mov	word[esi + 2], TCP_TIMEOUT
1218
 
1219
	inc	ecx
1220
	; Now get buffer location, and copy buffer across. argh! more copying,,
1221
	mov	edi, resendBuffer - IPBUFFSIZE
1222
 
1223
    @@: add	edi, IPBUFFSIZE
1224
	loop	@b
1225
 
1226
	; we have dest buffer location in edi
1227
	pop	eax
1228
	; convert source buffer pointer eax to the absolute address
1229
	mov	ecx, IPBUFFSIZE
1230
	mul	ecx
1231
	add	eax, IPbuffs
1232
	mov	esi, eax
1233
 
1234
	; do copy
1235
	mov	ecx, IPBUFFSIZE
1236
;        cld
1237
	rep	movsb
1238
 
1239
  .exit:
1240
	xor	eax, eax
1241
	ret
1242
 
1243
  .error:
1244
	or	eax, -1
1245
	ret
1246
endp
1247
 
1248
 
1249
 
1250
;***************************************************************************
1251
;   Function
1252
;      checksum
1253
;
1254
;   Description
1255
;       checkAdd1,checkAdd2, checkSize1, checkSize2, checkResult
1256
;       Dont break anything; Most registers are used by the caller
1257
;       This code is derived from the 'C' source, cksum.c, in the book
1258
;       Internetworking with TCP/IP Volume II by D.E. Comer
1259
;
1260
;***************************************************************************
1261
 
1262
 
1263
checksum:
1264
    pusha
1265
    mov     eax, [checkAdd1]
1266
    xor     edx, edx		      ; edx is the accumulative checksum
1267
    xor     ebx, ebx
1268
    mov     cx, [checkSize1]
1269
    shr     cx, 1
1270
    jz	    cs1_1
1271
 
1272
cs1:
1273
    mov     bh, [eax]
1274
    mov     bl, [eax + 1]
1275
 
1276
    add     eax, 2
1277
    add     edx, ebx
1278
 
1279
    loopw   cs1
1280
 
1281
cs1_1:
1282
    and     word [checkSize1], 0x01
1283
    jz	    cs_test2
1284
 
1285
    mov     bh, [eax]
1286
    xor     bl, bl
1287
 
1288
    add     edx, ebx
1289
 
1290
cs_test2:
1291
    mov     cx, [checkSize2]
1292
    cmp     cx, 0
1293
    jz	    cs_exit			; Finished if no 2nd buffer
1294
 
1295
    mov     eax, [checkAdd2]
1296
 
1297
    shr     cx, 1
1298
    jz	    cs2_1
1299
 
1300
cs2:
1301
    mov     bh, [eax]
1302
    mov     bl, [eax + 1]
1303
 
1304
    add     eax, 2
1305
    add     edx, ebx
1306
 
1307
    loopw   cs2
1308
 
1309
cs2_1:
1310
    and     word [checkSize2], 0x01
1311
    jz	    cs_exit
1312
 
1313
    mov     bh, [eax]
1314
    xor     bl, bl
1315
 
1316
    add     edx, ebx
1317
 
1318
cs_exit:
1319
    mov     ebx, edx
1320
 
1321
    shr     ebx, 16
1322
    and     edx, 0xffff
1323
    add     edx, ebx
1324
    mov     eax, edx
1325
    shr     eax, 16
1326
    add     edx, eax
1327
    not     dx
1328
 
1329
    mov     [checkResult], dx
1330
    popa
1331
    ret
1332
 
1333
 
1334
 
1335
 
1336
 
1337
TCP_HANDLER:
1338
;;; TODO: write code here
1339
 
1340
    call    kernel_free
1341
    add     esp, 4 ; pop (balance stack)
1342
 
1343
ret
1344