Subversion Repositories Kolibri OS

Rev

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