Subversion Repositories Kolibri OS

Rev

Rev 5594 | Rev 5984 | 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
 
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
 
3589 Serge 122
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_pull_out_of_band\n"
3555 Serge 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
5201 serge 146
TCP_drop:    ; FIXME CHECKME TODO
3555 Serge 147
 
3589 Serge 148
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_drop: %x\n", eax
3555 Serge 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
 
4423 Serge 155
        push    eax
3555 Serge 156
        call    TCP_output
4423 Serge 157
        pop     eax
3555 Serge 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
 
3725 Serge 169
;        mov     [eax + SOCKET.errorcode], ebx
3555 Serge 170
 
171
 
172
 
173
 
4423 Serge 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:
3555 Serge 184
 
4423 Serge 185
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_disconnect: %x\n", eax
3555 Serge 186
 
4423 Serge 187
        cmp     [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
188
        jb      TCP_close       ; Connection not yet synchronised, just get rid of the socket
3555 Serge 189
 
4423 Serge 190
; TODO: implement LINGER
3555 Serge 191
 
4423 Serge 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
 
3555 Serge 205
;-------------------------
206
;
207
; TCP_close
208
;
209
;  IN:  eax = socket ptr
4423 Serge 210
;  OUT: /
3555 Serge 211
;
212
;-------------------------
213
align 4
214
TCP_close:
215
 
3589 Serge 216
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_close: %x\n", eax
3555 Serge 217
 
218
;;; TODO: update RTT and mean deviation
219
;;; TODO: update slow start threshold
220
 
221
        call    SOCKET_is_disconnected
4423 Serge 222
        call    SOCKET_free
3555 Serge 223
 
4423 Serge 224
        xor     eax, eax
225
 
3555 Serge 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
 
3589 Serge 246
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_outflags: socket=%x flags=%x\n", eax, dl
3555 Serge 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
 
269
;---------------------------------------
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
;
278
;--------------------------------------
279
align 4
280
TCP_respond:
281
 
3589 Serge 282
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: socket=%x flags=%x\n", ebx, cl
3555 Serge 283
 
284
;---------------------
285
; Create the IP packet
286
 
287
        push    cx ebx
288
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
289
        mov     edx, [ebx + IP_SOCKET.LocalIP]
5594 serge 290
        mov     ebx, [ebx + IP_SOCKET.device]
3555 Serge 291
        mov     ecx, sizeof.TCP_header
292
        mov     di, IP_PROTO_TCP shl 8 + 128
293
        call    IPv4_output
294
        jz      .error
295
        pop     esi cx
5565 serge 296
        push    eax
3555 Serge 297
 
298
;-----------------------------------------------
299
; Fill in the TCP header by using the socket ptr
300
 
301
        mov     ax, [esi + TCP_SOCKET.LocalPort]
302
        stosw
303
        mov     ax, [esi + TCP_SOCKET.RemotePort]
304
        stosw
305
        mov     eax, [esi + TCP_SOCKET.SND_NXT]
306
        bswap   eax
307
        stosd
308
        mov     eax, [esi + TCP_SOCKET.RCV_NXT]
309
        bswap   eax
310
        stosd
311
        mov     al, 0x50        ; Dataoffset: 20 bytes (TCP_header.DataOffset)
312
        stosb
313
        mov     al, cl
314
        stosb
315
;        mov     ax, [esi + TCP_SOCKET.RCV_WND]
316
;        rol     ax, 8
317
        mov     ax, 0x00a0      ;;;;;;; FIXME
318
        stosw                   ; window
319
        xor     eax, eax
320
        stosd                   ; checksum + urgentpointer
321
 
322
;---------------------
323
; Fill in the checksum
324
 
325
  .checksum:
326
        sub     edi, sizeof.TCP_header
327
        mov     ecx, sizeof.TCP_header
328
        xchg    esi, edi
329
        TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
330
        mov     [esi+TCP_header.Checksum], dx
331
 
332
;--------------------
333
; And send the segment
334
 
335
        call    [ebx + NET_DEVICE.transmit]
3725 Serge 336
        test    eax, eax
337
        jnz     @f
338
        call    NET_ptr_to_num4
339
        inc     [TCP_segments_tx + edi]
340
       @@:
3555 Serge 341
        ret
342
 
343
  .error:
3589 Serge 344
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: failed\n"
3555 Serge 345
        add     esp, 2 + 4
346
 
347
        ret
348
 
349
 
350
 
351
 
352
 
353
 
354
 
355
 
356
;-------------------------
357
; TCP_respond_segment:
358
;
359
;  IN:  edx = segment ptr (a previously received segment)
360
;       edi = ptr to dest and src IPv4 addresses
361
;        cl = flags
362
 
363
align 4
364
TCP_respond_segment:
365
 
3589 Serge 366
        DEBUGF  DEBUG_NETWORK_VERBOSE,"TCP_respond_segment: frame=%x flags=%x\n", edx, cl
3555 Serge 367
 
368
;---------------------
369
; Create the IP packet
370
 
371
        push    cx edx
3908 Serge 372
        mov     edx, [edi + 4]
3555 Serge 373
        mov     eax, [edi]
374
        mov     ecx, sizeof.TCP_header
375
        mov     di, IP_PROTO_TCP shl 8 + 128
5594 serge 376
        xor     ebx, ebx                        ;;; fixme
3555 Serge 377
        call    IPv4_output
378
        jz      .error
379
        pop     esi cx
380
 
5565 serge 381
        push    eax
3555 Serge 382
 
383
;---------------------------------------------------
384
; Fill in the TCP header by using a received segment
385
 
386
        mov     ax, [esi + TCP_header.DestinationPort]
387
        stosw
388
        mov     ax, [esi + TCP_header.SourcePort]
389
        stosw
390
        mov     eax, [esi + TCP_header.AckNumber]
391
        bswap   eax
392
        stosd
393
        xor     eax, eax
394
        stosd
395
        mov     al, 0x50        ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4)
396
        stosb
397
        mov     al, cl
398
        stosb
399
        mov     ax, 1280
400
        rol     ax, 8
401
        stosw                   ; window
402
        xor     eax, eax
403
        stosd                   ; checksum + urgentpointer
404
 
405
;---------------------
406
; Fill in the checksum
407
 
408
        lea     esi, [edi - sizeof.TCP_header]
409
        mov     ecx, sizeof.TCP_header
410
        TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\      ; FIXME
411
                     (esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
412
        mov     [esi + TCP_header.Checksum], dx
413
 
414
;--------------------
415
; And send the segment
416
 
417
        call    [ebx + NET_DEVICE.transmit]
3725 Serge 418
        test    eax, eax
419
        jnz     @f
420
        call    NET_ptr_to_num4
421
        inc     [TCP_segments_tx + edi]
422
       @@:
3555 Serge 423
        ret
424
 
425
  .error:
3589 Serge 426
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_respond_segment: failed\n"
3555 Serge 427
        add     esp, 2+4
428
 
429
        ret
430
 
431
 
432
macro   TCPT_RANGESET   timer, value, min, max {
433
 
434
local   .min
435
local   .max
436
local   .done
437
 
438
        cmp     value, min
439
        jb      .min
440
        cmp     value, max
441
        ja      .max
442
 
443
        mov     timer, value
444
        jmp     .done
445
 
446
  .min:
447
        mov     timer, value
448
        jmp     .done
449
 
450
  .max:
451
        mov     timer, value
452
        jmp     .done
453
 
454
  .done:
455
}
456
 
457
 
458
align 4
459
TCP_set_persist:
460
 
3589 Serge 461
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_set_persist\n"
3555 Serge 462
 
463
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive
464
 
3626 Serge 465
        test    [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
466
        jnz     .exit
3555 Serge 467
 
468
; calculate RTO
469
        push    ebx
470
        mov     ebx, [eax + TCP_SOCKET.t_srtt]
471
        shr     ebx, 2
472
        add     ebx, [eax + TCP_SOCKET.t_rttvar]
473
        shr     ebx, 1
474
 
475
        mov     cl, [eax + TCP_SOCKET.t_rxtshift]
476
        shl     ebx, cl
477
 
478
; Start/restart persistance timer.
479
 
480
        TCPT_RANGESET   [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
3626 Serge 481
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
3555 Serge 482
        pop     ebx
483
 
484
        cmp     [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
485
        jae     @f
486
        inc     [eax + TCP_SOCKET.t_rxtshift]
487
      @@:
3626 Serge 488
  .exit:
3555 Serge 489
 
490
        ret
491
 
492
 
493
 
494
; eax = rtt
495
; ebx = socket ptr
496
 
497
align 4
498
TCP_xmit_timer:
499
 
3589 Serge 500
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax
3555 Serge 501
 
502
;TODO: update stats
503
 
504
        cmp     [ebx + TCP_SOCKET.t_rtt], 0
505
        je      .no_rtt_yet
506
 
507
; srtt is stored as a fixed point with 3 bits after the binary point.
508
; The following magic is equivalent of the smoothing algorithm in rfc793 with an alpha of .875
509
; (srtt = rtt/8 + srtt*7/8 in fixed point)
510
; Adjust rtt to origin 0.
511
 
512
        push    ecx
513
        mov     ecx, [ebx + TCP_SOCKET.t_srtt]
514
        shr     ecx, TCP_RTT_SHIFT
515
        sub     eax, ecx
516
        dec     eax
517
        pop     ecx
518
 
519
        add     [ebx + TCP_SOCKET.t_srtt], eax
520
        ja      @f
521
        mov     [ebx + TCP_SOCKET.t_srtt], 1
522
  @@:
523
 
524
; We accumulate a smoothed rtt variance (actually, a smoothed mean difference),
525
; then set the retransmit timer to smoothed rtt + 4 times the smoothed variance.
526
; rttvar is stored as fixed point with 2 bits after the binary point.
527
; The following is equivalent to rfc793 smoothing with an alpha of .75
528
; (rttvar = rttvar*3/4 + delta/4) (delta = eax)
529
 
530
; get abs(eax)
531
        push    edx
532
        cdq
533
        xor     eax, edx
534
        sub     eax, edx
535
 
536
        mov     edx, [ebx + TCP_SOCKET.t_rttvar]
537
        shr     edx, TCP_RTTVAR_SHIFT
538
        sub     eax, edx
539
        pop     edx
540
 
541
        add     [ebx + TCP_SOCKET.t_rttvar], eax
542
        ja      @f
543
        mov     [ebx + TCP_SOCKET.t_rttvar], 1
544
  @@:
545
        ret
546
 
547
 
548
  .no_rtt_yet:
549
 
550
        push    ecx
551
        mov     ecx, eax
552
        shl     ecx, TCP_RTT_SHIFT
553
        mov     [ebx + TCP_SOCKET.t_srtt], ecx
554
 
555
        shl     eax, TCP_RTTVAR_SHIFT - 1
556
        mov     [ebx + TCP_SOCKET.t_rttvar], eax
557
        pop     ecx
558
 
559
        ret
560
 
561
 
562
 
563
 
564
; eax = max segment size
565
; ebx = socket ptr
566
align 4
567
TCP_mss:
568
 
569
        cmp     eax, 1420                               ; FIXME
570
        jbe     @f
571
        mov     eax, 1420
572
  @@:
573
        mov     [ebx + TCP_SOCKET.t_maxseg], eax
574
 
575
 
576
        ret
577
 
578
 
579
 
580
 
581
; ebx = socket ptr
582
; edx = segment ptr
583
align 4
584
TCP_reassemble:
585
 
586
 
587
 
588
        ret
589