Subversion Repositories Kolibri OS

Rev

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