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