Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1763 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
2362 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved.    ;;
1763 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
3143 hidnplayr 6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
1763 hidnplayr 7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
9
;;                                                                 ;;
10
;;    Based on the code of 4.4BSD                                  ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1733 hidnplayr 16
 
1763 hidnplayr 17
$Revision: 3143 $
1733 hidnplayr 18
 
2955 hidnplayr 19
align 4
20
iglobal
21
        TCP_backoff     db 0,1,2,3,4,5,6,6,6,6,6,6,6
22
endg
23
 
2390 hidnplayr 24
macro   TCP_checksum IP1, IP2 {
1733 hidnplayr 25
 
26
;-------------
27
; Pseudoheader
28
 
2390 hidnplayr 29
        ; protocol type
30
        mov     edx, IP_PROTO_TCP
1733 hidnplayr 31
 
2390 hidnplayr 32
        ; source address
33
        add     dl, byte [IP1+1]
34
        adc     dh, byte [IP1+0]
35
        adc     dl, byte [IP1+3]
36
        adc     dh, byte [IP1+2]
1733 hidnplayr 37
 
2390 hidnplayr 38
        ; destination address
39
        adc     dl, byte [IP2+1]
40
        adc     dh, byte [IP2+0]
41
        adc     dl, byte [IP2+3]
42
        adc     dh, byte [IP2+2]
1733 hidnplayr 43
 
2390 hidnplayr 44
        ; size
45
        adc     dl, cl
46
        adc     dh, ch
1733 hidnplayr 47
 
2390 hidnplayr 48
        adc     edx, 0
49
 
1733 hidnplayr 50
;---------------------
51
; Real header and data
52
 
2390 hidnplayr 53
        push    esi
54
        call    checksum_1
55
        call    checksum_2
56
        pop     esi
1733 hidnplayr 57
 
2390 hidnplayr 58
}       ; returns in dx only
1733 hidnplayr 59
 
60
 
61
 
62
 
2390 hidnplayr 63
macro   TCP_sendseqinit ptr {
1733 hidnplayr 64
 
2390 hidnplayr 65
        push    edi                     ;;;; i dont like this static use of edi
66
        mov     edi, [ptr + TCP_SOCKET.ISS]
67
        mov     [ptr + TCP_SOCKET.SND_UP], edi
68
        mov     [ptr + TCP_SOCKET.SND_MAX], edi
69
        mov     [ptr + TCP_SOCKET.SND_NXT], edi
70
        mov     [ptr + TCP_SOCKET.SND_UNA], edi
71
        pop     edi
1733 hidnplayr 72
 
73
}
74
 
75
 
76
 
2390 hidnplayr 77
macro   TCP_rcvseqinit ptr {
1733 hidnplayr 78
 
2390 hidnplayr 79
        push    edi
80
        mov     edi, [ptr + TCP_SOCKET.IRS]
81
        inc     edi
82
        mov     [ptr + TCP_SOCKET.RCV_NXT], edi
83
        mov     [ptr + TCP_SOCKET.RCV_ADV], edi
84
        pop     edi
1733 hidnplayr 85
 
86
}
87
 
88
 
89
 
2930 hidnplayr 90
macro   TCP_init_socket socket {
1733 hidnplayr 91
 
2612 hidnplayr 92
        mov     [socket + TCP_SOCKET.t_maxseg], TCP_mss_default
2953 hidnplayr 93
        mov     [socket + TCP_SOCKET.t_flags], TF_REQ_SCALE or TF_REQ_TSTMP
1733 hidnplayr 94
 
2612 hidnplayr 95
        mov     [socket + TCP_SOCKET.t_srtt], TCP_time_srtt_default
96
        mov     [socket + TCP_SOCKET.t_rttvar], TCP_time_rtt_default * 4
97
        mov     [socket + TCP_SOCKET.t_rttmin], TCP_time_re_min
98
;;; TODO: TCP_time_rangeset
1733 hidnplayr 99
 
2612 hidnplayr 100
        mov     [socket + TCP_SOCKET.SND_CWND], TCP_max_win shl TCP_max_winshift
101
        mov     [socket + TCP_SOCKET.SND_SSTHRESH], TCP_max_win shl TCP_max_winshift
1733 hidnplayr 102
 
103
 
2612 hidnplayr 104
}
1733 hidnplayr 105
 
106
 
107
;---------------------------
108
;
109
; TCP_pull_out_of_band
110
;
111
; IN:  eax =
112
;      ebx = socket ptr
113
;      edx = tcp packet ptr
114
;
115
; OUT: /
116
;
117
;---------------------------
118
 
119
align 4
120
TCP_pull_out_of_band:
121
 
2390 hidnplayr 122
        DEBUGF  1,"TCP_pull_out_of_band\n"
1733 hidnplayr 123
 
2390 hidnplayr 124
        ;;;; 1282-1305
1733 hidnplayr 125
 
2390 hidnplayr 126
        ret
1733 hidnplayr 127
 
128
 
129
 
130
 
131
 
132
 
133
 
134
 
135
;-------------------------
136
;
137
; TCP_drop
138
;
139
;  IN:  eax = socket ptr
140
;       ebx = error number
141
;
142
;  OUT: eax = socket ptr
143
;
144
;-------------------------
145
align 4
146
TCP_drop:
147
 
2891 hidnplayr 148
        DEBUGF  1,"TCP_drop: %x\n", eax
1733 hidnplayr 149
 
2390 hidnplayr 150
        cmp     [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
151
        jb      .no_syn_received
1733 hidnplayr 152
 
2390 hidnplayr 153
        mov     [eax + TCP_SOCKET.t_state], TCPS_CLOSED
1733 hidnplayr 154
 
2390 hidnplayr 155
        call    TCP_output
1733 hidnplayr 156
 
157
;;; TODO: update stats
158
 
2390 hidnplayr 159
        jmp     TCP_close
1733 hidnplayr 160
 
161
  .no_syn_received:
162
 
163
;;; TODO: update stats
164
 
165
;;; TODO: check if error code is "Connection timed out' and handle accordingly
166
 
2390 hidnplayr 167
        mov     [eax + SOCKET.errorcode], ebx
1733 hidnplayr 168
 
169
 
170
 
171
 
172
 
173
 
174
 
175
 
176
;-------------------------
177
;
178
; TCP_close
179
;
180
;  IN:  eax = socket ptr
181
;  OUT: eax = socket ptr
182
;
183
;-------------------------
184
align 4
185
TCP_close:
186
 
2869 hidnplayr 187
        DEBUGF  1,"TCP_close: %x\n", eax
1733 hidnplayr 188
 
189
;;; TODO: update RTT and mean deviation
190
;;; TODO: update slow start threshold
191
 
2390 hidnplayr 192
        call    SOCKET_is_disconnected
1733 hidnplayr 193
 
2390 hidnplayr 194
        ret
1733 hidnplayr 195
 
196
 
197
 
2869 hidnplayr 198
;-------------------------
199
;
200
; TCP_disconnect
201
;
202
;  IN:  eax = socket ptr
203
;  OUT: eax = socket ptr
204
;
205
;-------------------------
206
align 4
207
TCP_disconnect:
1733 hidnplayr 208
 
2891 hidnplayr 209
        DEBUGF  1,"TCP_disconnect: %x\n", eax
1733 hidnplayr 210
 
2869 hidnplayr 211
        cmp     [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
212
        jb      TCP_close
1733 hidnplayr 213
 
214
 
2869 hidnplayr 215
; TODO: implement LINGER ?
1733 hidnplayr 216
 
2869 hidnplayr 217
        call    SOCKET_is_disconnecting
218
        call    TCP_usrclosed
219
        call    TCP_output
1733 hidnplayr 220
 
2869 hidnplayr 221
        ret
1733 hidnplayr 222
 
2869 hidnplayr 223
 
224
 
1733 hidnplayr 225
;-------------------------
226
;
2869 hidnplayr 227
; TCP_usrclose
228
;
229
;  IN:  eax = socket ptr
230
;
231
;-------------------------
232
align 4
233
TCP_usrclosed:
234
 
2891 hidnplayr 235
        DEBUGF  1,"TCP_usrclosed: %x\n", eax
2890 hidnplayr 236
 
2869 hidnplayr 237
        push    ebx
238
        mov     ebx, [eax + TCP_SOCKET.t_state]
239
        mov     ebx, dword [.switch + ebx*4]
240
        jmp     ebx
241
 
242
  .switch:
243
 
244
        dd      .close                  ; TCPS_CLOSED
245
        dd      .close                  ; TCPS_LISTEN
246
        dd      .close                  ; TCPS_SYN_SENT
247
        dd      .wait1                  ; TCPS_SYN_RECEIVED
248
        dd      .wait1                  ; TCPS_ESTABLISHED
249
        dd      .last_ack               ; TCPS_CLOSE_WAIT
250
        dd      .ret                    ; TCPS_FIN_WAIT_1
251
        dd      .ret                    ; TCPS_CLOSING
252
        dd      .ret                    ; TCPS_LAST_ACK
253
        dd      .disc                   ; TCPS_FIN_WAIT_2
254
        dd      .disc                   ; TCPS_TIMED_WAIT
255
 
256
 
257
  .close:
258
        pop     ebx
259
        mov     [eax + TCP_SOCKET.t_state], TCPS_CLOSED
260
        call    TCP_close
261
        ret
262
 
263
  .wait1:
264
        pop     ebx
265
        mov     [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
266
        ret
267
 
268
  .last_ack:
269
        pop     ebx
270
        mov     [eax + TCP_SOCKET.t_state], TCPS_LAST_ACK
271
        ret
272
 
273
  .disc:
274
        call    SOCKET_is_disconnected
275
  .ret:
276
        pop     ebx
277
        ret
278
 
279
 
280
;-------------------------
281
;
1733 hidnplayr 282
; TCP_outflags
283
;
284
;  IN:  eax = socket ptr
285
;
286
;  OUT: edx = flags
287
;
288
;-------------------------
289
align 4
290
TCP_outflags:
291
 
2390 hidnplayr 292
        mov     edx, [eax + TCP_SOCKET.t_state]
293
        movzx   edx, byte [edx + .flaglist]
1733 hidnplayr 294
 
2891 hidnplayr 295
        DEBUGF  1,"TCP_outflags: socket=%x flags=%x\n", eax, dl
1733 hidnplayr 296
 
2390 hidnplayr 297
        ret
1733 hidnplayr 298
 
299
  .flaglist:
300
 
2390 hidnplayr 301
        db      TH_RST + TH_ACK         ; TCPS_CLOSED
302
        db      0                       ; TCPS_LISTEN
303
        db      TH_SYN                  ; TCPS_SYN_SENT
304
        db      TH_SYN + TH_ACK         ; TCPS_SYN_RECEIVED
305
        db               TH_ACK         ; TCPS_ESTABLISHED
306
        db               TH_ACK         ; TCPS_CLOSE_WAIT
2890 hidnplayr 307
        db      TH_FIN + TH_ACK         ; TCPS_FIN_WAIT_1
308
        db      TH_FIN + TH_ACK         ; TCPS_CLOSING
309
        db      TH_FIN + TH_ACK         ; TCPS_LAST_ACK
2390 hidnplayr 310
        db               TH_ACK         ; TCPS_FIN_WAIT_2
311
        db               TH_ACK         ; TCPS_TIMED_WAIT
1733 hidnplayr 312
 
313
 
314
 
315
 
316
 
317
 
318
;---------------------------------------
319
;
1830 hidnplayr 320
; The fast way to send an ACK/RST/keepalive segment
1733 hidnplayr 321
;
3143 hidnplayr 322
; TCP_respond
1733 hidnplayr 323
;
324
;  IN:  ebx = socket ptr
325
;        cl = flags
326
;
327
;--------------------------------------
328
align 4
3143 hidnplayr 329
TCP_respond:
1733 hidnplayr 330
 
2891 hidnplayr 331
        DEBUGF  1,"TCP_respond_socket: socket=%x flags=%x\n", ebx, cl
1733 hidnplayr 332
 
333
;---------------------
334
; Create the IP packet
335
 
2390 hidnplayr 336
        push    cx ebx
337
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
2877 hidnplayr 338
        mov     edx, [ebx + IP_SOCKET.LocalIP]
2390 hidnplayr 339
        mov     ecx, sizeof.TCP_header
2877 hidnplayr 340
        mov     di, IP_PROTO_TCP shl 8 + 128
2390 hidnplayr 341
        call    IPv4_output
342
        test    edi, edi
343
        jz      .error
344
        pop     esi cx
345
        push    edx eax
1733 hidnplayr 346
 
347
;-----------------------------------------------
348
; Fill in the TCP header by using the socket ptr
349
 
2390 hidnplayr 350
        mov     ax, [esi + TCP_SOCKET.LocalPort]
351
        stosw
352
        mov     ax, [esi + TCP_SOCKET.RemotePort]
353
        stosw
354
        mov     eax, [esi + TCP_SOCKET.SND_NXT]
355
        bswap   eax
356
        stosd
357
        mov     eax, [esi + TCP_SOCKET.RCV_NXT]
358
        bswap   eax
359
        stosd
360
        mov     al, 0x50        ; Dataoffset: 20 bytes (TCP_header.DataOffset)
361
        stosb
362
        mov     al, cl
363
        stosb
1830 hidnplayr 364
;        mov     ax, [esi + TCP_SOCKET.RCV_WND]
365
;        rol     ax, 8
2390 hidnplayr 366
        mov     ax, 0x00a0      ;;;;;;; FIXME
367
        stosw                   ; window
368
        xor     eax, eax
369
        stosd                   ; checksum + urgentpointer
1733 hidnplayr 370
 
371
;---------------------
372
; Fill in the checksum
373
 
374
  .checksum:
2390 hidnplayr 375
        sub     edi, sizeof.TCP_header
376
        mov     ecx, sizeof.TCP_header
377
        xchg    esi, edi
378
        TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
379
        mov     [esi+TCP_header.Checksum], dx
1733 hidnplayr 380
 
381
;--------------------
382
; And send the segment
383
 
2390 hidnplayr 384
        call    [ebx + NET_DEVICE.transmit]
385
        ret
1733 hidnplayr 386
 
387
  .error:
2891 hidnplayr 388
        DEBUGF  1,"TCP_respond_socket: failed\n"
389
        add     esp, 2 + 4
1733 hidnplayr 390
 
2390 hidnplayr 391
        ret
1733 hidnplayr 392
 
393
 
394
 
395
 
396
 
397
 
398
 
399
 
400
;-------------------------
401
; TCP_respond.segment:
402
;
2600 hidnplayr 403
;  IN:  edx = segment ptr (a previously received segment)
2308 hidnplayr 404
;       edi = ptr to dest and src IPv4 addresses
1733 hidnplayr 405
;        cl = flags
406
 
407
align 4
408
TCP_respond_segment:
409
 
2891 hidnplayr 410
        DEBUGF  1,"TCP_respond_segment: frame=%x flags=%c\n", edx, cl
1733 hidnplayr 411
 
412
;---------------------
413
; Create the IP packet
414
 
2600 hidnplayr 415
        push    cx edx
2390 hidnplayr 416
        mov     ebx, [edi + 4]
417
        mov     eax, [edi]
418
        mov     ecx, sizeof.TCP_header
419
        mov     di , IP_PROTO_TCP shl 8 + 128
420
        call    IPv4_output
421
        jz      .error
2600 hidnplayr 422
        pop     esi cx
1733 hidnplayr 423
 
2390 hidnplayr 424
        push    edx eax
1733 hidnplayr 425
 
426
;---------------------------------------------------
427
; Fill in the TCP header by using a received segment
428
 
2390 hidnplayr 429
        mov     ax, [esi + TCP_header.DestinationPort]
430
        stosw
431
        mov     ax, [esi + TCP_header.SourcePort]
432
        stosw
433
        mov     eax, [esi + TCP_header.AckNumber]
434
        bswap   eax
435
        stosd
436
        xor     eax, eax
437
        stosd
438
        mov     al, 0x50        ; Dataoffset: 20 bytes (sizeof.TCP_header)
439
        stosb
440
        mov     al, cl
441
        stosb
442
        mov     ax, 1280
443
        rol     ax, 8
444
        stosw                   ; window
445
        xor     eax, eax
446
        stosd                   ; checksum + urgentpointer
1733 hidnplayr 447
 
448
;---------------------
449
; Fill in the checksum
450
 
451
  .checksum:
2390 hidnplayr 452
        lea     esi, [edi - sizeof.TCP_header]
453
        mov     ecx, sizeof.TCP_header
454
        TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\      ; FIXME
455
                     (esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
456
        mov     [esi+TCP_header.Checksum], dx
1733 hidnplayr 457
 
458
;--------------------
459
; And send the segment
460
 
2390 hidnplayr 461
        call    [ebx + NET_DEVICE.transmit]
462
        ret
1733 hidnplayr 463
 
464
  .error:
2891 hidnplayr 465
        DEBUGF  1,"TCP_respond_segment: failed\n"
2390 hidnplayr 466
        add     esp, 2+4
1733 hidnplayr 467
 
2390 hidnplayr 468
        ret
2362 hidnplayr 469
 
470
 
2955 hidnplayr 471
macro   TCPT_RANGESET   timer, value, min, max {
2362 hidnplayr 472
 
2955 hidnplayr 473
local   .min
474
local   .max
475
local   .done
2362 hidnplayr 476
 
2955 hidnplayr 477
        cmp     value, min
478
        jb      .min
479
        cmp     value, max
480
        ja      .max
481
 
482
        mov     timer, value
483
        jmp     .done
484
 
485
  .min:
486
        mov     timer, value
487
        jmp     .done
488
 
489
  .max:
490
        mov     timer, value
491
        jmp     .done
492
 
493
  .done:
494
}
495
 
496
 
497
align 4
498
TCP_set_persist:
499
 
2937 hidnplayr 500
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive
501
 
2955 hidnplayr 502
        cmp     [eax + TCP_SOCKET.timer_retransmission], 0
503
        jg      @f
2937 hidnplayr 504
 
505
; calculate RTO
506
 
2955 hidnplayr 507
        push    ebx
508
        mov     ebx, [eax + TCP_SOCKET.t_srtt]
509
        shr     ebx, 2
510
        add     ebx, [eax + TCP_SOCKET.t_rttvar]
511
        shr     ebx, 1
2937 hidnplayr 512
 
2955 hidnplayr 513
        mov     cl, [eax + TCP_SOCKET.t_rxtshift]
514
        shl     ebx, cl
2937 hidnplayr 515
 
516
; Start/restart persistance timer.
517
 
2955 hidnplayr 518
        TCPT_RANGESET   [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
2362 hidnplayr 519
 
2955 hidnplayr 520
        pop     ebx
2937 hidnplayr 521
 
2955 hidnplayr 522
        cmp     [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
523
        jae     @f
524
        inc     [eax + TCP_SOCKET.t_rxtshift]
525
      @@:
2930 hidnplayr 526
 
2955 hidnplayr 527
        ret
2937 hidnplayr 528
 
529
 
2955 hidnplayr 530
 
2930 hidnplayr 531
; eax = rtt
532
; ebx = socket ptr
533
 
534
align 4
535
TCP_xmit_timer:
536
 
2948 hidnplayr 537
        DEBUGF  1,"TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax
538
 
2937 hidnplayr 539
;TODO: update stats
2930 hidnplayr 540
 
2937 hidnplayr 541
        cmp     [ebx + TCP_SOCKET.t_rtt], 0
542
        je      .no_rtt_yet
543
 
544
; srtt is stored as a fixed point with 3 bits after the binary point.
545
; The following magic is equivalent of the smoothing algorithm in rfc793 with an alpha of .875
546
; (srtt = rtt/8 + srtt*7/8 in fixed point)
547
; Adjust rtt to origin 0.
548
 
549
        push    ecx
550
        mov     ecx, [ebx + TCP_SOCKET.t_srtt]
551
        shr     ecx, TCP_RTT_SHIFT
552
        sub     eax, ecx
553
        dec     eax
554
        pop     ecx
555
 
556
        add     [ebx + TCP_SOCKET.t_srtt], eax
557
        ja      @f
558
        mov     [ebx + TCP_SOCKET.t_srtt], 1
559
  @@:
560
 
561
; We accumulate a smoothed rtt variance (actually, a smoothed mean difference),
562
; then set the retransmit timer to smoothed rtt + 4 times the smoothed variance.
563
; rttvar is stored as fixed point with 2 bits after the binary point.
564
; The following is equivalent to rfc793 smoothing with an alpha of .75
565
; (rttvar = rttvar*3/4 + delta/4) (delta = eax)
566
 
567
; get abs(eax)
568
        push    edx
569
        cdq
570
        xor     eax, edx
571
        sub     eax, edx
572
 
573
        mov     edx, [ebx + TCP_SOCKET.t_rttvar]
574
        shr     edx, TCP_RTTVAR_SHIFT
575
        sub     eax, edx
576
        pop     edx
577
 
578
        add     [ebx + TCP_SOCKET.t_rttvar], eax
579
        ja      @f
580
        mov     [ebx + TCP_SOCKET.t_rttvar], 1
581
  @@:
582
        ret
583
 
584
 
585
  .no_rtt_yet:
586
 
587
        push    ecx
588
        mov     ecx, eax
589
        shl     ecx, TCP_RTT_SHIFT
590
        mov     [ebx + TCP_SOCKET.t_srtt], ecx
591
 
592
        shl     eax, TCP_RTTVAR_SHIFT - 1
593
        mov     [ebx + TCP_SOCKET.t_rttvar], eax
594
        pop     ecx
595
 
596
        ret