Subversion Repositories Kolibri OS

Rev

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