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