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