Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1763 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3251 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
1763 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
3143 hidnplayr 6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
1763 hidnplayr 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: 3251 $
18
 
1733 hidnplayr 19
;-----------------------------------------------------------------
20
;
21
; TCP_output
22
;
23
; IN:  eax = socket pointer
24
;
25
; OUT: /
26
;
27
;-----------------------------------------------------------------
28
align 4
29
TCP_output:
30
 
2891 hidnplayr 31
        DEBUGF 1,"TCP_output: socket=%x\n", eax
1733 hidnplayr 32
 
2891 hidnplayr 33
        pusha
34
        lea     ecx, [eax + SOCKET.mutex]
35
        call    mutex_lock
36
        popa
37
 
1733 hidnplayr 38
; We'll detect the length of the data to be transmitted, and flags to be used
39
; If there is some data, or any critical controls to send (SYN / RST), then transmit
40
; Otherwise, investigate further
41
 
2402 hidnplayr 42
        mov     ebx, [eax + TCP_SOCKET.SND_MAX]
43
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
2951 hidnplayr 44
        jbe     .not_idle
1733 hidnplayr 45
 
2402 hidnplayr 46
        mov     ebx, [eax + TCP_SOCKET.t_idle]
47
        cmp     ebx, [eax + TCP_SOCKET.t_rxtcur]
48
        jbe     .not_idle
1733 hidnplayr 49
 
50
; We have been idle for a while and no ACKS are expected to clock out any data we send..
51
; Slow start to get ack "clock" running again.
52
 
2402 hidnplayr 53
        mov     ebx, [eax + TCP_SOCKET.t_maxseg]
54
        mov     [eax + TCP_SOCKET.SND_CWND], ebx
1733 hidnplayr 55
 
56
  .not_idle:
57
  .again:
2937 hidnplayr 58
        mov     [eax + TCP_SOCKET.temp_bits], 0
2890 hidnplayr 59
 
2402 hidnplayr 60
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]         ; calculate offset (71)
61
        sub     ebx, [eax + TCP_SOCKET.SND_UNA]         ;
1733 hidnplayr 62
 
2402 hidnplayr 63
        mov     ecx, [eax + TCP_SOCKET.SND_WND]         ; determine window
64
        cmp     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
65
        jb      @f                                      ;
66
        mov     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
67
       @@:                                              ;
1733 hidnplayr 68
 
2402 hidnplayr 69
        call    TCP_outflags                            ; flags in dl
1733 hidnplayr 70
 
1761 hidnplayr 71
;------------------------
72
; data being forced out ?
73
 
1733 hidnplayr 74
; If in persist timeout with window of 0, send 1 byte.
75
; Otherwise, if window is small but nonzero, and timer expired,
76
; we will send what we can and go to transmit state
77
 
2951 hidnplayr 78
        cmp     [eax + TCP_SOCKET.t_force], 0
79
        je      .no_force
1733 hidnplayr 80
 
3146 hidnplayr 81
        DEBUGF 1,"TCP_output: forcing data out\n"
82
 
2402 hidnplayr 83
        test    ecx, ecx
84
        jnz     .no_zero_window
1733 hidnplayr 85
 
2402 hidnplayr 86
        cmp     ebx, [eax + STREAM_SOCKET.snd.size]
87
        jae     @f
1733 hidnplayr 88
 
2890 hidnplayr 89
        and     dl, not (TH_FIN)
1733 hidnplayr 90
 
91
       @@:
2402 hidnplayr 92
        inc     ecx
93
        jmp     .no_force
1733 hidnplayr 94
 
95
  .no_zero_window:
2402 hidnplayr 96
        mov     [eax + TCP_SOCKET.timer_persist], 0
97
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
1733 hidnplayr 98
 
1761 hidnplayr 99
  .no_force:
1733 hidnplayr 100
 
1761 hidnplayr 101
;--------------------------------
102
; Calculate how much data to send (106)
1733 hidnplayr 103
 
2402 hidnplayr 104
        mov     esi, [eax + STREAM_SOCKET.snd.size]
105
        cmp     esi, ecx
106
        jb      @f
107
        mov     esi, ecx
1733 hidnplayr 108
       @@:
2402 hidnplayr 109
        sub     esi, ebx
1733 hidnplayr 110
 
2612 hidnplayr 111
 
1761 hidnplayr 112
;------------------------
113
; check for window shrink (107)
1733 hidnplayr 114
 
1761 hidnplayr 115
; If FIN has been set, but not ACKed, but we havent been called to retransmit, esi will be -1
1733 hidnplayr 116
; Otherwise, window shrank after we sent into it.
117
 
2612 hidnplayr 118
        jae     .not_persist
1761 hidnplayr 119
 
120
; enter persist state
2402 hidnplayr 121
        xor     esi, esi
1733 hidnplayr 122
 
1761 hidnplayr 123
; If window shrank to 0
2402 hidnplayr 124
        test    ecx, ecx
125
        jnz     @f
1733 hidnplayr 126
 
1761 hidnplayr 127
; cancel pending retransmit
2402 hidnplayr 128
        mov     [eax + TCP_SOCKET.timer_retransmission], 0
1733 hidnplayr 129
 
1761 hidnplayr 130
; pull SND_NXT back to (closed) window, We will enter persist state below.
2402 hidnplayr 131
        push    [eax + TCP_SOCKET.SND_UNA]
132
        pop     [eax + TCP_SOCKET.SND_NXT]
1733 hidnplayr 133
       @@:
134
 
1761 hidnplayr 135
; If window didn't close completely, just wait for an ACK
1733 hidnplayr 136
 
2612 hidnplayr 137
  .not_persist:
1733 hidnplayr 138
 
1761 hidnplayr 139
;---------------------------
140
; Send one segment at a time (124)
141
 
2402 hidnplayr 142
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
143
        jbe     @f
1733 hidnplayr 144
 
2402 hidnplayr 145
        mov     esi, [eax + TCP_SOCKET.t_maxseg]
2937 hidnplayr 146
        or      [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
1733 hidnplayr 147
       @@:
148
 
1761 hidnplayr 149
;--------------------------------------------
150
; Turn of FIN flag if send buffer not emptied (128)
1733 hidnplayr 151
 
2402 hidnplayr 152
        mov     edi, [eax + TCP_SOCKET.SND_NXT]
153
        add     edi, esi
154
        sub     edi, [eax + TCP_SOCKET.SND_UNA]
2890 hidnplayr 155
        cmp     edi, [eax + STREAM_SOCKET.snd.size]
156
        jae     @f
2402 hidnplayr 157
        and     dl, not (TH_FIN)
1733 hidnplayr 158
 
159
       @@:
160
 
1761 hidnplayr 161
;-------------------------------
162
; calculate window advertisement (130)
1733 hidnplayr 163
 
2402 hidnplayr 164
        mov     ecx, SOCKET_MAXDATA
165
        sub     ecx, [eax + STREAM_SOCKET.rcv.size]
1733 hidnplayr 166
 
167
;------------------------------
1761 hidnplayr 168
; Sender silly window avoidance (131)
1733 hidnplayr 169
 
2402 hidnplayr 170
        test    esi, esi
171
        jz      .len_zero
1761 hidnplayr 172
 
2402 hidnplayr 173
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
2888 hidnplayr 174
        je      TCP_send
1733 hidnplayr 175
 
2890 hidnplayr 176
        add     ebx, esi                                ; offset + length
177
        cmp     ebx, [eax + STREAM_SOCKET.snd.size]
178
        jb      @f
179
 
2402 hidnplayr 180
        test    [eax + TCP_SOCKET.t_flags], TF_NODELAY
2890 hidnplayr 181
        jnz     TCP_send
182
 
183
        mov     ebx, [eax + TCP_SOCKET.SND_MAX]
184
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
185
        je      TCP_send
2362 hidnplayr 186
       @@:
1733 hidnplayr 187
 
2402 hidnplayr 188
        test    [eax + TCP_SOCKET.t_force], -1  ;;;
2888 hidnplayr 189
        jnz     TCP_send
1733 hidnplayr 190
 
2402 hidnplayr 191
        mov     ebx, [eax + TCP_SOCKET.max_sndwnd]
192
        shr     ebx, 1
193
        cmp     esi, ebx
2888 hidnplayr 194
        jae     TCP_send
1733 hidnplayr 195
 
2402 hidnplayr 196
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]
197
        cmp     ebx, [eax + TCP_SOCKET.SND_MAX]
2888 hidnplayr 198
        jb      TCP_send
1733 hidnplayr 199
 
1761 hidnplayr 200
  .len_zero:
201
 
1733 hidnplayr 202
;----------------------------------------
1761 hidnplayr 203
; Check if a window update should be sent (154)
1733 hidnplayr 204
 
2951 hidnplayr 205
        DEBUGF  1,"TCP_output: window=%d\n", ecx
206
 
207
; Compare available window to amount of window known to peer (as advertised window less next expected input)
208
; If the difference is at least two max size segments, or at least 50% of the maximum possible window,
209
; Then we want to send a window update to the peer.
210
 
2402 hidnplayr 211
        test    ecx, ecx
212
        jz      .no_window
1733 hidnplayr 213
 
2402 hidnplayr 214
        push    ecx
215
        mov     cl, [eax + TCP_SOCKET.RCV_SCALE]
216
        mov     ebx, TCP_max_win
217
        shl     ebx, cl
218
        pop     ecx
219
        cmp     ebx, ecx
2951 hidnplayr 220
        jb      @f
221
        mov     ebx, ecx
222
       @@:
223
        sub     ebx, [eax + TCP_SOCKET.RCV_ADV]
224
        add     ebx, [eax + TCP_SOCKET.RCV_NXT]
1733 hidnplayr 225
 
2951 hidnplayr 226
        mov     edi, [eax + TCP_SOCKET.t_maxseg]
227
        shl     edi, 1
2362 hidnplayr 228
 
2951 hidnplayr 229
;        cmp     ebx, edi
230
;        jae     TCP_send
2362 hidnplayr 231
 
2951 hidnplayr 232
;        cmp     ebx, [eax + TCP_SOCKET.]    ;;; TODO: check with receive buffer high water mark
233
;        jae     TCP_send
2362 hidnplayr 234
 
1733 hidnplayr 235
  .no_window:
236
 
237
;--------------------------
1761 hidnplayr 238
; Should a segment be sent? (174)
1733 hidnplayr 239
 
2951 hidnplayr 240
        DEBUGF  1,"TCP_output: 174\n"
241
 
2402 hidnplayr 242
        test    [eax + TCP_SOCKET.t_flags], TF_ACKNOW   ; we need to ACK
2888 hidnplayr 243
        jnz     TCP_send
1733 hidnplayr 244
 
2402 hidnplayr 245
        test    dl, TH_SYN + TH_RST                     ; we need to send a SYN or RST
2888 hidnplayr 246
        jnz     TCP_send
1733 hidnplayr 247
 
2402 hidnplayr 248
        mov     ebx, [eax + TCP_SOCKET.SND_UP]          ; when urgent pointer is beyond start of send bufer
249
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
2888 hidnplayr 250
        ja      TCP_send
1733 hidnplayr 251
 
2402 hidnplayr 252
        test    dl, TH_FIN
253
        jz      .enter_persist  ; no reason to send, enter persist state
1733 hidnplayr 254
 
1761 hidnplayr 255
; FIN was set, only send if not already sent, or on retransmit
256
 
2402 hidnplayr 257
        test    [eax + TCP_SOCKET.t_flags], TF_SENTFIN
2890 hidnplayr 258
        jz      TCP_send
1733 hidnplayr 259
 
2402 hidnplayr 260
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]
261
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
2888 hidnplayr 262
        je      TCP_send
1733 hidnplayr 263
 
264
;--------------------
1761 hidnplayr 265
; Enter persist state (191)
1733 hidnplayr 266
 
267
  .enter_persist:
268
 
2402 hidnplayr 269
        cmp     [eax + STREAM_SOCKET.snd.size], 0       ; Data ready to send?
270
        jne     @f
271
        cmp     [eax + TCP_SOCKET.timer_retransmission], 0
272
        jne     @f
273
        cmp     [eax + TCP_SOCKET.timer_persist], 0     ; Persist timer already expired?
274
        jne     @f
2362 hidnplayr 275
 
2891 hidnplayr 276
        DEBUGF  1,"TCP_output: Entering persist state\n"
1733 hidnplayr 277
 
2402 hidnplayr 278
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
2955 hidnplayr 279
        call    TCP_set_persist
2362 hidnplayr 280
       @@:
1733 hidnplayr 281
 
1761 hidnplayr 282
;----------------------------
283
; No reason to send a segment (219)
284
 
2891 hidnplayr 285
        DEBUGF  1,"TCP_output: No reason to send a segment\n"
1733 hidnplayr 286
 
2402 hidnplayr 287
        pusha
288
        lea     ecx, [eax + SOCKET.mutex]
289
        call    mutex_unlock
290
        popa
1733 hidnplayr 291
 
2402 hidnplayr 292
        ret
1733 hidnplayr 293
 
294
 
1761 hidnplayr 295
 
296
 
297
 
298
 
299
 
300
 
301
 
1733 hidnplayr 302
;-----------------------------------------------
303
;
1761 hidnplayr 304
; Send a segment (222)
1733 hidnplayr 305
;
306
; eax = socket pointer
1761 hidnplayr 307
; esi = data len
1733 hidnplayr 308
;  dl = flags
309
;
310
;-----------------------------------------------
2888 hidnplayr 311
align 4
312
TCP_send:
1733 hidnplayr 313
 
2891 hidnplayr 314
        DEBUGF  1,"TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl
1733 hidnplayr 315
 
2890 hidnplayr 316
        push    eax                     ; save socket ptr
2937 hidnplayr 317
        push    esi                     ; and data length too
2402 hidnplayr 318
        mov     edi, sizeof.TCP_header  ; edi will contain headersize
1733 hidnplayr 319
 
320
;------------------------------------
321
; Send options with first SYN segment
322
 
2402 hidnplayr 323
        test    dl, TH_SYN
324
        jz      .options_done
1733 hidnplayr 325
 
2402 hidnplayr 326
        push    [eax + TCP_SOCKET.ISS]
327
        pop     [eax + TCP_SOCKET.SND_NXT]
1733 hidnplayr 328
 
2402 hidnplayr 329
        test    [eax + TCP_SOCKET.t_flags], TF_NOOPT
330
        jnz     .options_done
1733 hidnplayr 331
 
2951 hidnplayr 332
        mov     ecx, 1460                              ;;;; FIXME: use routing blablabla to determine MSS
2402 hidnplayr 333
        or      ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
334
        bswap   ecx
335
        push    ecx
336
        add     di, 4
1733 hidnplayr 337
 
2951 hidnplayr 338
        DEBUGF  1,"TCP_send: added maxseg option\n"
339
 
2402 hidnplayr 340
        test    [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
2952 hidnplayr 341
        jz      .no_scale
1733 hidnplayr 342
 
2402 hidnplayr 343
        test    dl, TH_ACK
2952 hidnplayr 344
        jz      .scale_opt
1733 hidnplayr 345
 
2402 hidnplayr 346
        test    [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
2952 hidnplayr 347
        jz      .no_scale
1733 hidnplayr 348
 
349
  .scale_opt:
2952 hidnplayr 350
        mov     cl, [eax + TCP_SOCKET.request_r_scale]
351
        mov     ch, TCP_OPT_NOP
352
        pushw   cx
353
        pushw   TCP_OPT_WINDOW + 3 shl 8
2402 hidnplayr 354
        add     di, 4
1733 hidnplayr 355
 
2951 hidnplayr 356
        DEBUGF  1,"TCP_send: added scale option\n"
357
 
2952 hidnplayr 358
  .no_scale:
1733 hidnplayr 359
  .no_syn:
360
 
361
;------------------------------------
362
; Make the timestamp option if needed
363
 
2402 hidnplayr 364
        test    [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
365
        jz      .no_timestamp
1733 hidnplayr 366
 
2402 hidnplayr 367
        test    dl, TH_RST
368
        jnz     .no_timestamp
1733 hidnplayr 369
 
2402 hidnplayr 370
        test    dl, TH_ACK
371
        jz      .timestamp
1733 hidnplayr 372
 
2402 hidnplayr 373
        test    [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
374
        jz      .no_timestamp
1733 hidnplayr 375
 
376
  .timestamp:
2951 hidnplayr 377
        pushd   0
378
        pushd   [timer_ticks]
379
        pushd   TCP_OPT_NOP + TCP_OPT_NOP shl 8 + TCP_OPT_TIMESTAMP shl 16 + 10 shl 24
380
        add     di, 12
1733 hidnplayr 381
 
2951 hidnplayr 382
        DEBUGF  1,"TCP_send: added timestamp\n"
383
 
1733 hidnplayr 384
  .no_timestamp:
385
 
2402 hidnplayr 386
        ; 
1733 hidnplayr 387
 
1761 hidnplayr 388
  .options_done:
389
 
390
; eax = socket ptr
391
; edx = flags
392
; edi = header size
393
; esi = data len
394
 
395
;---------------------------------------------
396
; check if we dont exceed the max segment size (270)
397
 
2402 hidnplayr 398
        add     esi, edi                        ; total TCP segment size
399
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
400
        jbe     .no_overflow
1761 hidnplayr 401
 
2402 hidnplayr 402
        mov     esi, [eax + TCP_SOCKET.t_maxseg]
2937 hidnplayr 403
        or      [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
1761 hidnplayr 404
  .no_overflow:
405
 
406
;-----------------------------------------------------------------
1733 hidnplayr 407
; Start by pushing all TCP header values in reverse order on stack
1761 hidnplayr 408
; (essentially, creating the tcp header on the stack!)
1733 hidnplayr 409
 
2402 hidnplayr 410
        pushw   0       ;        .UrgentPointer          dw ?
411
        pushw   0       ;        .Checksum               dw ?
2888 hidnplayr 412
        pushw   0x00a0  ;        .Window                 dw ?    ;;;;;;; FIXME (370)
2402 hidnplayr 413
        shl     edi, 2  ;        .DataOffset             db ?  only 4 left-most bits
414
        shl     dx, 8
415
        or      dx, di  ;        .Flags                  db ?
416
        pushw   dx
2888 hidnplayr 417
        shr     edi, 2  ;        .DataOffset             db ?
1733 hidnplayr 418
 
2402 hidnplayr 419
        push    [eax + TCP_SOCKET.RCV_NXT]      ;        .AckNumber              dd ?
420
        ntohd   [esp]
1733 hidnplayr 421
 
2402 hidnplayr 422
        push    [eax + TCP_SOCKET.SND_NXT]      ;        .SequenceNumber         dd ?
423
        ntohd   [esp]
1733 hidnplayr 424
 
2402 hidnplayr 425
        push    [eax + TCP_SOCKET.RemotePort]   ;        .DestinationPort        dw ?
426
        push    [eax + TCP_SOCKET.LocalPort]    ;        .SourcePort             dw ?
1733 hidnplayr 427
 
2890 hidnplayr 428
        push    edi                     ; header size
1733 hidnplayr 429
 
1761 hidnplayr 430
;---------------------
1733 hidnplayr 431
; Create the IP packet
1761 hidnplayr 432
 
2402 hidnplayr 433
        mov     ecx, esi
1761 hidnplayr 434
 
2877 hidnplayr 435
        mov     ebx, [eax + SOCKET.device]
436
        mov     edx, [eax + IP_SOCKET.LocalIP]  ; source ip
2402 hidnplayr 437
        mov     eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
438
        mov     di, IP_PROTO_TCP shl 8 + 128
439
        call    IPv4_output
2555 hidnplayr 440
        jz      .ip_error
1733 hidnplayr 441
 
442
;-----------------------------------------
443
; Move TCP header from stack to TCP packet
444
 
2402 hidnplayr 445
        push    ecx
2890 hidnplayr 446
        mov     ecx, [esp + 4]
447
        lea     esi, [esp + 8]
448
        shr     ecx, 2                  ; count is in bytes, we will work with dwords
2402 hidnplayr 449
        rep     movsd
2890 hidnplayr 450
        pop     ecx                     ; full TCP packet size
1733 hidnplayr 451
 
2890 hidnplayr 452
        pop     esi                     ; headersize
453
        add     esp, esi                ; remove it from stack
1733 hidnplayr 454
 
2890 hidnplayr 455
        push    edx                     ; packet size for send proc
456
        push    eax                     ; packet ptr for send proc
1733 hidnplayr 457
 
2402 hidnplayr 458
        mov     edx, edi                ; begin of data
459
        sub     edx, esi                ; begin of packet (edi = begin of data)
460
        push    ecx
461
        sub     ecx, esi                ; data size
1733 hidnplayr 462
 
463
;--------------
464
; Copy the data
465
 
466
; eax = ptr to ring struct
467
; ecx = buffer size
468
; edi = ptr to buffer
469
 
2937 hidnplayr 470
        mov     eax, [esp + 16]                 ; get socket ptr
1761 hidnplayr 471
 
2888 hidnplayr 472
        push    edx
2937 hidnplayr 473
        push    [eax + TCP_SOCKET.SND_NXT]      ; we'll need this for timing the transmission
2888 hidnplayr 474
        test    ecx, ecx
475
        jz      .nodata
2893 hidnplayr 476
        mov     edx, [eax + TCP_SOCKET.SND_NXT]
2937 hidnplayr 477
        add     [eax + TCP_SOCKET.SND_NXT], ecx ; update sequence number <<< CHECKME
478
        sub     edx, [eax + TCP_SOCKET.SND_UNA] ; offset
2402 hidnplayr 479
        add     eax, STREAM_SOCKET.snd
480
        call    SOCKET_ring_read
2888 hidnplayr 481
  .nodata:
2937 hidnplayr 482
        pop     edi
2402 hidnplayr 483
        pop     esi                             ; begin of data
484
        pop     ecx                             ; full packet size
2938 hidnplayr 485
        mov     eax, [esp + 12]                 ; socket ptr
1733 hidnplayr 486
 
1761 hidnplayr 487
;----------------------------------
2937 hidnplayr 488
; initialize retransmit timer (400)
1761 hidnplayr 489
 
2937 hidnplayr 490
;TODO: check t_force and persist
491
 
492
        test    [esi + TCP_header.Flags], TH_SYN + TH_FIN       ; syn and fin take a sequence number
2402 hidnplayr 493
        jz      @f
2937 hidnplayr 494
        inc     [eax + TCP_SOCKET.SND_NXT]
2402 hidnplayr 495
        test    [esi + TCP_header.Flags], TH_FIN
496
        jz      @f
2937 hidnplayr 497
        or      [eax + TCP_SOCKET.t_flags], TF_SENTFIN          ; if we sent a fin, set the sentfin flag
1733 hidnplayr 498
       @@:
499
 
2402 hidnplayr 500
        mov     edx, [eax + TCP_SOCKET.SND_NXT]
2937 hidnplayr 501
        cmp     edx, [eax + TCP_SOCKET.SND_MAX]                 ; is this a retransmission?
2402 hidnplayr 502
        jbe     @f
2937 hidnplayr 503
        mov     [eax + TCP_SOCKET.SND_MAX], edx                 ; [eax + TCP_SOCKET.SND_NXT] from before we updated it
1733 hidnplayr 504
 
2937 hidnplayr 505
        cmp     [eax + TCP_SOCKET.t_rtt], 0                     ; are we currently timing anything?
506
        je      @f
507
        mov     [eax + TCP_SOCKET.t_rtt], 1                     ; nope, start transmission timer
508
        mov     [eax + TCP_SOCKET.t_rtseq], edi
509
;TODO: update stats
1733 hidnplayr 510
       @@:
511
 
1761 hidnplayr 512
; set retransmission timer if not already set, and not doing an ACK or keepalive probe
1733 hidnplayr 513
 
2937 hidnplayr 514
        cmp     [eax + TCP_SOCKET.timer_retransmission], 0 ;;;; FIXME
515
        ja      .retransmit_set
1761 hidnplayr 516
 
2937 hidnplayr 517
        cmp     edx, [eax + TCP_SOCKET.SND_UNA]                 ; edx is still [eax + TCP_SOCKET.SND_NXT]
2402 hidnplayr 518
        je      .retransmit_set
1761 hidnplayr 519
 
2402 hidnplayr 520
        mov     edx, [eax + TCP_SOCKET.t_rxtcur]
2955 hidnplayr 521
        mov     [eax + TCP_SOCKET.timer_retransmission], edx
1761 hidnplayr 522
 
2402 hidnplayr 523
        cmp     [eax + TCP_SOCKET.timer_persist], 0
2890 hidnplayr 524
        jne     .retransmit_set
2402 hidnplayr 525
        mov     [eax + TCP_SOCKET.timer_persist], 0
526
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
1761 hidnplayr 527
 
528
  .retransmit_set:
529
 
1733 hidnplayr 530
;--------------------
531
; Create the checksum
532
 
2402 hidnplayr 533
        TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
534
        mov     [esi + TCP_header.Checksum], dx
1733 hidnplayr 535
 
2940 hidnplayr 536
; unlock socket
537
        lea     ecx, [eax + SOCKET.mutex]
538
        call    mutex_unlock
539
 
1733 hidnplayr 540
;----------------
541
; Send the packet
542
 
2891 hidnplayr 543
        DEBUGF  1,"TCP_send: Sending with device %x\n", ebx
2402 hidnplayr 544
        call    [ebx + NET_DEVICE.transmit]
2890 hidnplayr 545
        jnz     .send_error
2937 hidnplayr 546
 
547
;---------------
548
; Ok, data sent!
549
 
550
        pop     ecx
2890 hidnplayr 551
        pop     eax
552
 
553
        inc     [TCP_segments_tx]       ; FIXME: correct interface?
554
 
2940 hidnplayr 555
; unlock socket
556
        lea     ecx, [eax + SOCKET.mutex]
557
        call    mutex_lock
558
 
2937 hidnplayr 559
; update advertised receive window
560
        test    ecx, ecx
561
        jz      @f
562
        add     ecx, [eax + TCP_SOCKET.RCV_NXT]
563
        cmp     ecx, [eax + TCP_SOCKET.RCV_ADV]
564
        jbe     @f
565
        mov     [eax + TCP_SOCKET.RCV_ADV], ecx
566
       @@:
2890 hidnplayr 567
 
2937 hidnplayr 568
; update last ack sent
2890 hidnplayr 569
        push    [eax + TCP_SOCKET.RCV_NXT]
570
        pop     [eax + TCP_SOCKET.last_ack_sent]
571
 
2937 hidnplayr 572
; and flags
2890 hidnplayr 573
        and     [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK)
574
 
2937 hidnplayr 575
        test    [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
576
        jnz     TCP_output.again
2890 hidnplayr 577
 
578
; unlock socket
579
        lea     ecx, [eax + SOCKET.mutex]
580
        call    mutex_unlock
2932 hidnplayr 581
 
2891 hidnplayr 582
        DEBUGF 1,"TCP_send: success!\n"
2890 hidnplayr 583
 
584
        xor     eax, eax
2402 hidnplayr 585
        ret
1733 hidnplayr 586
 
587
 
2555 hidnplayr 588
  .ip_error:
2402 hidnplayr 589
        pop     ecx
590
        add     esp, ecx
2937 hidnplayr 591
        add     esp, 4
2402 hidnplayr 592
        pop     eax
1733 hidnplayr 593
 
2629 hidnplayr 594
        mov     [eax + TCP_SOCKET.timer_retransmission], TCP_time_re_min
595
 
2890 hidnplayr 596
; unlock socket
2402 hidnplayr 597
        lea     ecx, [eax + SOCKET.mutex]
598
        call    mutex_unlock
2932 hidnplayr 599
 
2891 hidnplayr 600
        DEBUGF 1,"TCP_send: IP error\n"
1733 hidnplayr 601
 
2890 hidnplayr 602
        or      eax, -1
2402 hidnplayr 603
        ret
604
 
2890 hidnplayr 605
  .send_error:
2940 hidnplayr 606
        add     esp, 8
2937 hidnplayr 607
 
2891 hidnplayr 608
        DEBUGF 1,"TCP_send: sending failed\n"
2402 hidnplayr 609
 
2890 hidnplayr 610
        or      eax, -2
611
        ret
2888 hidnplayr 612