Subversion Repositories Kolibri OS

Rev

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

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