Subversion Repositories Kolibri OS

Rev

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

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