Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
3545 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
4850 mario79 17
$Revision: 5842 $
3545 hidnplayr 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
 
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
 
3556 hidnplayr 122
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_pull_out_of_band\n"
3545 hidnplayr 123
 
124
        ;;;; 1282-1305
125
 
126
        ret
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
5015 hidnplayr 146
TCP_drop:    ; FIXME CHECKME TODO
3545 hidnplayr 147
 
3556 hidnplayr 148
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_drop: %x\n", eax
3545 hidnplayr 149
 
150
        cmp     [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
151
        jb      .no_syn_received
152
 
153
        mov     [eax + TCP_SOCKET.t_state], TCPS_CLOSED
154
 
4365 hidnplayr 155
        push    eax
3545 hidnplayr 156
        call    TCP_output
4365 hidnplayr 157
        pop     eax
3545 hidnplayr 158
 
159
;;; TODO: update stats
160
 
161
        jmp     TCP_close
162
 
163
  .no_syn_received:
164
 
165
;;; TODO: update stats
166
 
167
;;; TODO: check if error code is "Connection timed out' and handle accordingly
168
 
3674 hidnplayr 169
;        mov     [eax + SOCKET.errorcode], ebx
3545 hidnplayr 170
 
171
 
172
 
173
 
4366 hidnplayr 174
;-------------------------
175
;
176
; TCP_disconnect
177
;
178
;  IN:  eax = socket ptr
179
;  OUT: eax = socket ptr / 0
180
;
181
;-------------------------
182
align 4
183
TCP_disconnect:
3545 hidnplayr 184
 
4366 hidnplayr 185
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_disconnect: %x\n", eax
3545 hidnplayr 186
 
4366 hidnplayr 187
        cmp     [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
188
        jb      TCP_close       ; Connection not yet synchronised, just get rid of the socket
3545 hidnplayr 189
 
4366 hidnplayr 190
; TODO: implement LINGER
3545 hidnplayr 191
 
4366 hidnplayr 192
        call    SOCKET_is_disconnecting
193
        call    TCP_usrclosed
194
 
195
        test    eax, eax
196
        jz      @f
197
        push    eax
198
        call    TCP_output
199
        pop     eax
200
  @@:
201
 
202
        ret
203
 
204
 
3545 hidnplayr 205
;-------------------------
206
;
207
; TCP_close
208
;
209
;  IN:  eax = socket ptr
4366 hidnplayr 210
;  OUT: /
3545 hidnplayr 211
;
212
;-------------------------
213
align 4
214
TCP_close:
215
 
3556 hidnplayr 216
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_close: %x\n", eax
3545 hidnplayr 217
 
218
;;; TODO: update RTT and mean deviation
219
;;; TODO: update slow start threshold
220
 
221
        call    SOCKET_is_disconnected
4366 hidnplayr 222
        call    SOCKET_free
3545 hidnplayr 223
 
4366 hidnplayr 224
        xor     eax, eax
225
 
3545 hidnplayr 226
        ret
227
 
228
 
229
 
230
 
231
;-------------------------
232
;
233
; TCP_outflags
234
;
235
;  IN:  eax = socket ptr
236
;
237
;  OUT: edx = flags
238
;
239
;-------------------------
240
align 4
241
TCP_outflags:
242
 
243
        mov     edx, [eax + TCP_SOCKET.t_state]
244
        movzx   edx, byte [edx + .flaglist]
245
 
3556 hidnplayr 246
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_outflags: socket=%x flags=%x\n", eax, dl
3545 hidnplayr 247
 
248
        ret
249
 
250
  .flaglist:
251
 
252
        db      TH_RST + TH_ACK         ; TCPS_CLOSED
253
        db      0                       ; TCPS_LISTEN
254
        db      TH_SYN                  ; TCPS_SYN_SENT
255
        db      TH_SYN + TH_ACK         ; TCPS_SYN_RECEIVED
256
        db               TH_ACK         ; TCPS_ESTABLISHED
257
        db               TH_ACK         ; TCPS_CLOSE_WAIT
258
        db      TH_FIN + TH_ACK         ; TCPS_FIN_WAIT_1
259
        db      TH_FIN + TH_ACK         ; TCPS_CLOSING
260
        db      TH_FIN + TH_ACK         ; TCPS_LAST_ACK
261
        db               TH_ACK         ; TCPS_FIN_WAIT_2
262
        db               TH_ACK         ; TCPS_TIMED_WAIT
263
 
264
 
265
 
266
 
267
 
268
 
5842 hidnplayr 269
;-----------------------------------------------------------------
3545 hidnplayr 270
;
271
; The fast way to send an ACK/RST/keepalive segment
272
;
273
; TCP_respond
274
;
275
;  IN:  ebx = socket ptr
276
;        cl = flags
277
;
5842 hidnplayr 278
; OUT:  /
279
;
280
;-----------------------------------------------------------------
281
 
3545 hidnplayr 282
align 4
283
TCP_respond:
284
 
3556 hidnplayr 285
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: socket=%x flags=%x\n", ebx, cl
3545 hidnplayr 286
 
287
;---------------------
288
; Create the IP packet
289
 
290
        push    cx ebx
291
        mov     edx, [ebx + IP_SOCKET.LocalIP]
5842 hidnplayr 292
        mov     edi, [ebx + IP_SOCKET.RemoteIP]
293
        mov     al, [ebx + IP_SOCKET.ttl]
294
        mov     ah, IP_PROTO_TCP
295
        mov     ecx, sizeof.TCP_header
5584 hidnplayr 296
        mov     ebx, [ebx + IP_SOCKET.device]
3545 hidnplayr 297
        call    IPv4_output
298
        jz      .error
299
        pop     esi cx
5522 hidnplayr 300
        push    eax
3545 hidnplayr 301
 
302
;-----------------------------------------------
303
; Fill in the TCP header by using the socket ptr
304
 
305
        mov     ax, [esi + TCP_SOCKET.LocalPort]
306
        stosw
307
        mov     ax, [esi + TCP_SOCKET.RemotePort]
308
        stosw
309
        mov     eax, [esi + TCP_SOCKET.SND_NXT]
310
        bswap   eax
311
        stosd
312
        mov     eax, [esi + TCP_SOCKET.RCV_NXT]
313
        bswap   eax
314
        stosd
315
        mov     al, 0x50        ; Dataoffset: 20 bytes (TCP_header.DataOffset)
316
        stosb
317
        mov     al, cl
318
        stosb
319
;        mov     ax, [esi + TCP_SOCKET.RCV_WND]
320
;        rol     ax, 8
321
        mov     ax, 0x00a0      ;;;;;;; FIXME
322
        stosw                   ; window
323
        xor     eax, eax
324
        stosd                   ; checksum + urgentpointer
325
 
326
;---------------------
327
; Fill in the checksum
328
 
329
  .checksum:
330
        sub     edi, sizeof.TCP_header
331
        mov     ecx, sizeof.TCP_header
332
        xchg    esi, edi
333
        TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
334
        mov     [esi+TCP_header.Checksum], dx
335
 
336
;--------------------
337
; And send the segment
338
 
339
        call    [ebx + NET_DEVICE.transmit]
3644 hidnplayr 340
        test    eax, eax
341
        jnz     @f
342
        call    NET_ptr_to_num4
343
        inc     [TCP_segments_tx + edi]
344
       @@:
3545 hidnplayr 345
        ret
346
 
347
  .error:
3556 hidnplayr 348
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: failed\n"
3545 hidnplayr 349
        add     esp, 2 + 4
350
 
351
        ret
352
 
353
 
5842 hidnplayr 354
;-----------------------------------------------------------------
355
;
3545 hidnplayr 356
; TCP_respond_segment:
357
;
5842 hidnplayr 358
;  IN:  ebx = device ptr
359
;       edx = segment ptr (a previously received segment)
360
;       edi = ptr to IPv4 header
3545 hidnplayr 361
;        cl = flags
5842 hidnplayr 362
;
363
;  OUT: /
364
;
365
;-----------------------------------------------------------------
3545 hidnplayr 366
 
367
align 4
368
TCP_respond_segment:
369
 
5842 hidnplayr 370
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_segment: frame=%x flags=%x\n", edx, cl
3545 hidnplayr 371
 
372
;---------------------
373
; Create the IP packet
374
 
375
        push    cx edx
5842 hidnplayr 376
        mov     edx, [edi + IPv4_header.DestinationAddress]
377
        mov     edi, [edi + IPv4_header.SourceAddress]
3545 hidnplayr 378
        mov     ecx, sizeof.TCP_header
5842 hidnplayr 379
        mov     ax, IP_PROTO_TCP shl 8 + 128
3545 hidnplayr 380
        call    IPv4_output
381
        jz      .error
382
        pop     esi cx
383
 
5522 hidnplayr 384
        push    eax
3545 hidnplayr 385
 
386
;---------------------------------------------------
387
; Fill in the TCP header by using a received segment
388
 
389
        mov     ax, [esi + TCP_header.DestinationPort]
390
        stosw
391
        mov     ax, [esi + TCP_header.SourcePort]
392
        stosw
393
        mov     eax, [esi + TCP_header.AckNumber]
394
        bswap   eax
395
        stosd
396
        xor     eax, eax
397
        stosd
398
        mov     al, 0x50        ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4)
399
        stosb
400
        mov     al, cl
401
        stosb
402
        mov     ax, 1280
403
        rol     ax, 8
404
        stosw                   ; window
405
        xor     eax, eax
406
        stosd                   ; checksum + urgentpointer
407
 
408
;---------------------
409
; Fill in the checksum
410
 
411
        lea     esi, [edi - sizeof.TCP_header]
412
        mov     ecx, sizeof.TCP_header
413
        TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\      ; FIXME
414
                     (esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
415
        mov     [esi + TCP_header.Checksum], dx
416
 
417
;--------------------
418
; And send the segment
419
 
420
        call    [ebx + NET_DEVICE.transmit]
3644 hidnplayr 421
        test    eax, eax
422
        jnz     @f
423
        call    NET_ptr_to_num4
424
        inc     [TCP_segments_tx + edi]
425
       @@:
3545 hidnplayr 426
        ret
427
 
428
  .error:
3556 hidnplayr 429
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_segment: failed\n"
3545 hidnplayr 430
        add     esp, 2+4
431
 
432
        ret
433
 
434
 
435
macro   TCPT_RANGESET   timer, value, min, max {
436
 
437
local   .min
438
local   .max
439
local   .done
440
 
441
        cmp     value, min
442
        jb      .min
443
        cmp     value, max
444
        ja      .max
445
 
446
        mov     timer, value
447
        jmp     .done
448
 
449
  .min:
450
        mov     timer, value
451
        jmp     .done
452
 
453
  .max:
454
        mov     timer, value
455
        jmp     .done
456
 
457
  .done:
458
}
459
 
460
 
461
align 4
462
TCP_set_persist:
463
 
3556 hidnplayr 464
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_set_persist\n"
3545 hidnplayr 465
 
466
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive
467
 
3600 hidnplayr 468
        test    [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
469
        jnz     .exit
3545 hidnplayr 470
 
471
; calculate RTO
472
        push    ebx
473
        mov     ebx, [eax + TCP_SOCKET.t_srtt]
474
        shr     ebx, 2
475
        add     ebx, [eax + TCP_SOCKET.t_rttvar]
476
        shr     ebx, 1
477
 
478
        mov     cl, [eax + TCP_SOCKET.t_rxtshift]
479
        shl     ebx, cl
480
 
481
; Start/restart persistance timer.
482
 
483
        TCPT_RANGESET   [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
3600 hidnplayr 484
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
3545 hidnplayr 485
        pop     ebx
486
 
487
        cmp     [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
488
        jae     @f
489
        inc     [eax + TCP_SOCKET.t_rxtshift]
490
      @@:
3600 hidnplayr 491
  .exit:
3545 hidnplayr 492
 
493
        ret
494
 
495
 
496
 
497
; eax = rtt
498
; ebx = socket ptr
499
 
500
align 4
501
TCP_xmit_timer:
502
 
3556 hidnplayr 503
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax
3545 hidnplayr 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
 
553
        push    ecx
554
        mov     ecx, eax
555
        shl     ecx, TCP_RTT_SHIFT
556
        mov     [ebx + TCP_SOCKET.t_srtt], ecx
557
 
558
        shl     eax, TCP_RTTVAR_SHIFT - 1
559
        mov     [ebx + TCP_SOCKET.t_rttvar], eax
560
        pop     ecx
561
 
562
        ret
563
 
564
 
565
 
566
 
567
; eax = max segment size
568
; ebx = socket ptr
569
align 4
570
TCP_mss:
571
 
572
        cmp     eax, 1420                               ; FIXME
573
        jbe     @f
574
        mov     eax, 1420
575
  @@:
576
        mov     [ebx + TCP_SOCKET.t_maxseg], eax
577
 
578
 
579
        ret
580
 
581
 
582
 
583
 
584
; ebx = socket ptr
585
; edx = segment ptr
586
align 4
587
TCP_reassemble:
588
 
589
 
590
 
591
        ret
592