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