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