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