Subversion Repositories Kolibri OS

Rev

Rev 2952 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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