Subversion Repositories Kolibri OS

Rev

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

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