Subversion Repositories Kolibri OS

Rev

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

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