Subversion Repositories Kolibri OS

Rev

Rev 3144 | 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: 3146 $
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
 
198
 
199
;-------------------------
200
;
201
; TCP_outflags
202
;
203
;  IN:  eax = socket ptr
204
;
205
;  OUT: edx = flags
206
;
207
;-------------------------
208
align 4
209
TCP_outflags:
210
 
2390 hidnplayr 211
        mov     edx, [eax + TCP_SOCKET.t_state]
212
        movzx   edx, byte [edx + .flaglist]
1733 hidnplayr 213
 
2891 hidnplayr 214
        DEBUGF  1,"TCP_outflags: socket=%x flags=%x\n", eax, dl
1733 hidnplayr 215
 
2390 hidnplayr 216
        ret
1733 hidnplayr 217
 
218
  .flaglist:
219
 
2390 hidnplayr 220
        db      TH_RST + TH_ACK         ; TCPS_CLOSED
221
        db      0                       ; TCPS_LISTEN
222
        db      TH_SYN                  ; TCPS_SYN_SENT
223
        db      TH_SYN + TH_ACK         ; TCPS_SYN_RECEIVED
224
        db               TH_ACK         ; TCPS_ESTABLISHED
225
        db               TH_ACK         ; TCPS_CLOSE_WAIT
2890 hidnplayr 226
        db      TH_FIN + TH_ACK         ; TCPS_FIN_WAIT_1
227
        db      TH_FIN + TH_ACK         ; TCPS_CLOSING
228
        db      TH_FIN + TH_ACK         ; TCPS_LAST_ACK
2390 hidnplayr 229
        db               TH_ACK         ; TCPS_FIN_WAIT_2
230
        db               TH_ACK         ; TCPS_TIMED_WAIT
1733 hidnplayr 231
 
232
 
233
 
234
 
235
 
236
 
237
;---------------------------------------
238
;
1830 hidnplayr 239
; The fast way to send an ACK/RST/keepalive segment
1733 hidnplayr 240
;
3143 hidnplayr 241
; TCP_respond
1733 hidnplayr 242
;
243
;  IN:  ebx = socket ptr
244
;        cl = flags
245
;
246
;--------------------------------------
247
align 4
3143 hidnplayr 248
TCP_respond:
1733 hidnplayr 249
 
2891 hidnplayr 250
        DEBUGF  1,"TCP_respond_socket: socket=%x flags=%x\n", ebx, cl
1733 hidnplayr 251
 
252
;---------------------
253
; Create the IP packet
254
 
2390 hidnplayr 255
        push    cx ebx
256
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
2877 hidnplayr 257
        mov     edx, [ebx + IP_SOCKET.LocalIP]
2390 hidnplayr 258
        mov     ecx, sizeof.TCP_header
2877 hidnplayr 259
        mov     di, IP_PROTO_TCP shl 8 + 128
2390 hidnplayr 260
        call    IPv4_output
261
        test    edi, edi
262
        jz      .error
263
        pop     esi cx
264
        push    edx eax
1733 hidnplayr 265
 
266
;-----------------------------------------------
267
; Fill in the TCP header by using the socket ptr
268
 
2390 hidnplayr 269
        mov     ax, [esi + TCP_SOCKET.LocalPort]
270
        stosw
271
        mov     ax, [esi + TCP_SOCKET.RemotePort]
272
        stosw
273
        mov     eax, [esi + TCP_SOCKET.SND_NXT]
274
        bswap   eax
275
        stosd
276
        mov     eax, [esi + TCP_SOCKET.RCV_NXT]
277
        bswap   eax
278
        stosd
279
        mov     al, 0x50        ; Dataoffset: 20 bytes (TCP_header.DataOffset)
280
        stosb
281
        mov     al, cl
282
        stosb
1830 hidnplayr 283
;        mov     ax, [esi + TCP_SOCKET.RCV_WND]
284
;        rol     ax, 8
2390 hidnplayr 285
        mov     ax, 0x00a0      ;;;;;;; FIXME
286
        stosw                   ; window
287
        xor     eax, eax
288
        stosd                   ; checksum + urgentpointer
1733 hidnplayr 289
 
290
;---------------------
291
; Fill in the checksum
292
 
293
  .checksum:
2390 hidnplayr 294
        sub     edi, sizeof.TCP_header
295
        mov     ecx, sizeof.TCP_header
296
        xchg    esi, edi
297
        TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
298
        mov     [esi+TCP_header.Checksum], dx
1733 hidnplayr 299
 
300
;--------------------
301
; And send the segment
302
 
2390 hidnplayr 303
        call    [ebx + NET_DEVICE.transmit]
304
        ret
1733 hidnplayr 305
 
306
  .error:
2891 hidnplayr 307
        DEBUGF  1,"TCP_respond_socket: failed\n"
308
        add     esp, 2 + 4
1733 hidnplayr 309
 
2390 hidnplayr 310
        ret
1733 hidnplayr 311
 
312
 
313
 
314
 
315
 
316
 
317
 
318
 
319
;-------------------------
320
; TCP_respond.segment:
321
;
2600 hidnplayr 322
;  IN:  edx = segment ptr (a previously received segment)
2308 hidnplayr 323
;       edi = ptr to dest and src IPv4 addresses
1733 hidnplayr 324
;        cl = flags
325
 
326
align 4
327
TCP_respond_segment:
328
 
2891 hidnplayr 329
        DEBUGF  1,"TCP_respond_segment: frame=%x flags=%c\n", edx, cl
1733 hidnplayr 330
 
331
;---------------------
332
; Create the IP packet
333
 
2600 hidnplayr 334
        push    cx edx
2390 hidnplayr 335
        mov     ebx, [edi + 4]
336
        mov     eax, [edi]
337
        mov     ecx, sizeof.TCP_header
338
        mov     di , IP_PROTO_TCP shl 8 + 128
339
        call    IPv4_output
340
        jz      .error
2600 hidnplayr 341
        pop     esi cx
1733 hidnplayr 342
 
2390 hidnplayr 343
        push    edx eax
1733 hidnplayr 344
 
345
;---------------------------------------------------
346
; Fill in the TCP header by using a received segment
347
 
2390 hidnplayr 348
        mov     ax, [esi + TCP_header.DestinationPort]
349
        stosw
350
        mov     ax, [esi + TCP_header.SourcePort]
351
        stosw
352
        mov     eax, [esi + TCP_header.AckNumber]
353
        bswap   eax
354
        stosd
355
        xor     eax, eax
356
        stosd
357
        mov     al, 0x50        ; Dataoffset: 20 bytes (sizeof.TCP_header)
358
        stosb
359
        mov     al, cl
360
        stosb
361
        mov     ax, 1280
362
        rol     ax, 8
363
        stosw                   ; window
364
        xor     eax, eax
365
        stosd                   ; checksum + urgentpointer
1733 hidnplayr 366
 
367
;---------------------
368
; Fill in the checksum
369
 
370
  .checksum:
2390 hidnplayr 371
        lea     esi, [edi - sizeof.TCP_header]
372
        mov     ecx, sizeof.TCP_header
373
        TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\      ; FIXME
374
                     (esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
375
        mov     [esi+TCP_header.Checksum], dx
1733 hidnplayr 376
 
377
;--------------------
378
; And send the segment
379
 
2390 hidnplayr 380
        call    [ebx + NET_DEVICE.transmit]
381
        ret
1733 hidnplayr 382
 
383
  .error:
2891 hidnplayr 384
        DEBUGF  1,"TCP_respond_segment: failed\n"
2390 hidnplayr 385
        add     esp, 2+4
1733 hidnplayr 386
 
2390 hidnplayr 387
        ret
2362 hidnplayr 388
 
389
 
2955 hidnplayr 390
macro   TCPT_RANGESET   timer, value, min, max {
2362 hidnplayr 391
 
2955 hidnplayr 392
local   .min
393
local   .max
394
local   .done
2362 hidnplayr 395
 
2955 hidnplayr 396
        cmp     value, min
397
        jb      .min
398
        cmp     value, max
399
        ja      .max
400
 
401
        mov     timer, value
402
        jmp     .done
403
 
404
  .min:
405
        mov     timer, value
406
        jmp     .done
407
 
408
  .max:
409
        mov     timer, value
410
        jmp     .done
411
 
412
  .done:
413
}
414
 
415
 
416
align 4
417
TCP_set_persist:
418
 
2937 hidnplayr 419
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive
420
 
2955 hidnplayr 421
        cmp     [eax + TCP_SOCKET.timer_retransmission], 0
422
        jg      @f
2937 hidnplayr 423
 
424
; calculate RTO
425
 
2955 hidnplayr 426
        push    ebx
427
        mov     ebx, [eax + TCP_SOCKET.t_srtt]
428
        shr     ebx, 2
429
        add     ebx, [eax + TCP_SOCKET.t_rttvar]
430
        shr     ebx, 1
2937 hidnplayr 431
 
2955 hidnplayr 432
        mov     cl, [eax + TCP_SOCKET.t_rxtshift]
433
        shl     ebx, cl
2937 hidnplayr 434
 
435
; Start/restart persistance timer.
436
 
2955 hidnplayr 437
        TCPT_RANGESET   [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
2362 hidnplayr 438
 
2955 hidnplayr 439
        pop     ebx
2937 hidnplayr 440
 
2955 hidnplayr 441
        cmp     [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
442
        jae     @f
443
        inc     [eax + TCP_SOCKET.t_rxtshift]
444
      @@:
2930 hidnplayr 445
 
2955 hidnplayr 446
        ret
2937 hidnplayr 447
 
448
 
2955 hidnplayr 449
 
2930 hidnplayr 450
; eax = rtt
451
; ebx = socket ptr
452
 
453
align 4
454
TCP_xmit_timer:
455
 
2948 hidnplayr 456
        DEBUGF  1,"TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax
457
 
2937 hidnplayr 458
;TODO: update stats
2930 hidnplayr 459
 
2937 hidnplayr 460
        cmp     [ebx + TCP_SOCKET.t_rtt], 0
461
        je      .no_rtt_yet
462
 
463
; srtt is stored as a fixed point with 3 bits after the binary point.
464
; The following magic is equivalent of the smoothing algorithm in rfc793 with an alpha of .875
465
; (srtt = rtt/8 + srtt*7/8 in fixed point)
466
; Adjust rtt to origin 0.
467
 
468
        push    ecx
469
        mov     ecx, [ebx + TCP_SOCKET.t_srtt]
470
        shr     ecx, TCP_RTT_SHIFT
471
        sub     eax, ecx
472
        dec     eax
473
        pop     ecx
474
 
475
        add     [ebx + TCP_SOCKET.t_srtt], eax
476
        ja      @f
477
        mov     [ebx + TCP_SOCKET.t_srtt], 1
478
  @@:
479
 
480
; We accumulate a smoothed rtt variance (actually, a smoothed mean difference),
481
; then set the retransmit timer to smoothed rtt + 4 times the smoothed variance.
482
; rttvar is stored as fixed point with 2 bits after the binary point.
483
; The following is equivalent to rfc793 smoothing with an alpha of .75
484
; (rttvar = rttvar*3/4 + delta/4) (delta = eax)
485
 
486
; get abs(eax)
487
        push    edx
488
        cdq
489
        xor     eax, edx
490
        sub     eax, edx
491
 
492
        mov     edx, [ebx + TCP_SOCKET.t_rttvar]
493
        shr     edx, TCP_RTTVAR_SHIFT
494
        sub     eax, edx
495
        pop     edx
496
 
497
        add     [ebx + TCP_SOCKET.t_rttvar], eax
498
        ja      @f
499
        mov     [ebx + TCP_SOCKET.t_rttvar], 1
500
  @@:
501
        ret
502
 
503
 
504
  .no_rtt_yet:
505
 
506
        push    ecx
507
        mov     ecx, eax
508
        shl     ecx, TCP_RTT_SHIFT
509
        mov     [ebx + TCP_SOCKET.t_srtt], ecx
510
 
511
        shl     eax, TCP_RTTVAR_SHIFT - 1
512
        mov     [ebx + TCP_SOCKET.t_rttvar], eax
513
        pop     ecx
514
 
515
        ret
3144 hidnplayr 516
 
517
 
518
 
519
 
520
; eax = max segment size
521
; ebx = socket ptr
522
align 4
523
TCP_mss:
524
 
525
        cmp     eax, 1420                               ; FIXME
526
        jbe     @f
527
        mov     eax, 1420
528
  @@:
529
        mov     [ebx + TCP_SOCKET.t_maxseg], eax
530
 
531
 
532
        ret