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