Rev 1206 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1196 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
3 | ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; |
||
4 | ;; Distributed under terms of the GNU General Public License ;; |
||
5 | ;; ;; |
||
6 | ;; TCP.INC ;; |
||
7 | ;; ;; |
||
8 | ;; Part of the tcp/ip network stack for KolibriOS ;; |
||
9 | ;; ;; |
||
10 | ;; Written by hidnplayr@kolibrios.org ;; |
||
11 | ;; ;; |
||
12 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
13 | ;; Version 2, June 1991 ;; |
||
14 | ;; ;; |
||
15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
1159 | hidnplayr | 16 | |
1196 | hidnplayr | 17 | |
1206 | hidnplayr | 18 | $Revision: 1249 $ |
1159 | hidnplayr | 19 | |
20 | |||
21 | TCB_LISTEN equ 1 |
||
22 | TCB_SYN_SENT equ 2 |
||
23 | TCB_SYN_RECEIVED equ 3 |
||
24 | TCB_ESTABLISHED equ 4 |
||
25 | TCB_FIN_WAIT_1 equ 5 |
||
26 | TCB_FIN_WAIT_2 equ 6 |
||
27 | TCB_CLOSE_WAIT equ 7 |
||
28 | TCB_CLOSING equ 8 |
||
29 | TCB_LAST_ACK equ 9 |
||
30 | TCB_TIMED_WAIT equ 10 |
||
31 | TCB_CLOSED equ 11 |
||
32 | |||
1249 | hidnplayr | 33 | TH_FIN equ 1 shl 0 |
34 | TH_SYN equ 1 shl 1 |
||
35 | TH_RST equ 1 shl 2 |
||
36 | TH_PUSH equ 1 shl 3 |
||
37 | TH_ACK equ 1 shl 4 |
||
38 | TH_URG equ 1 shl 5 |
||
1159 | hidnplayr | 39 | |
1196 | hidnplayr | 40 | TWOMSL equ 10 ; # of secs to wait before closing socket |
1159 | hidnplayr | 41 | |
1196 | hidnplayr | 42 | TCP_RETRIES equ 5 ; Number of times to resend a Packet |
1249 | hidnplayr | 43 | TCP_TIMEOUT equ 10 ; resend if not replied to in 1/100 s |
1159 | hidnplayr | 44 | |
1196 | hidnplayr | 45 | TCP_QUEUE_SIZE equ 16 |
46 | |||
1249 | hidnplayr | 47 | |
1159 | hidnplayr | 48 | struct TCP_Packet |
49 | .SourcePort dw ? |
||
50 | .DestinationPort dw ? |
||
51 | .SequenceNumber dd ? |
||
52 | .AckNumber dd ? |
||
1196 | hidnplayr | 53 | .DataOffset db ? ; DataOffset[0-3 bits] and Reserved[4-7] |
54 | .Flags db ? ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN |
||
1159 | hidnplayr | 55 | .Window dw ? |
56 | .Checksum dw ? |
||
57 | .UrgentPointer dw ? |
||
58 | .Options rb 3 |
||
59 | .Padding db ? |
||
60 | .Data: |
||
61 | ends |
||
62 | |||
1196 | hidnplayr | 63 | align 4 |
64 | uglobal |
||
65 | TCP_PACKETS_TX rd MAX_IP |
||
66 | TCP_PACKETS_RX rd MAX_IP |
||
1159 | hidnplayr | 67 | |
1249 | hidnplayr | 68 | TCP_IN_QUEUE rd (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4 |
69 | TCP_OUT_QUEUE dd ? |
||
70 | rd (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4 |
||
1196 | hidnplayr | 71 | endg |
72 | |||
1249 | hidnplayr | 73 | align 4 |
74 | iglobal |
||
1196 | hidnplayr | 75 | |
1249 | hidnplayr | 76 | TCBStateHandler: |
1196 | hidnplayr | 77 | |
1249 | hidnplayr | 78 | dd stateTCB_LISTEN |
79 | dd stateTCB_SYN_SENT |
||
80 | dd stateTCB_SYN_RECEIVED |
||
81 | dd stateTCB_ESTABLISHED |
||
82 | dd stateTCB_FIN_WAIT_1 |
||
83 | dd stateTCB_FIN_WAIT_2 |
||
84 | dd stateTCB_CLOSE_WAIT |
||
85 | dd stateTCB_CLOSING |
||
86 | dd stateTCB_LAST_ACK |
||
87 | dd stateTCB_TIME_WAIT |
||
88 | dd stateTCB_CLOSED |
||
1196 | hidnplayr | 89 | |
1249 | hidnplayr | 90 | endg |
1196 | hidnplayr | 91 | |
1249 | hidnplayr | 92 | |
93 | macro inc_INET reg { |
||
94 | |||
95 | inc byte [reg + 0] |
||
96 | adc byte [reg + 1], 0 |
||
97 | adc byte [reg + 2], 0 |
||
98 | adc byte [reg + 3], 0 |
||
99 | |||
100 | } |
||
101 | |||
102 | |||
103 | macro add_INET reg { |
||
104 | |||
105 | rol ecx, 16 |
||
106 | adc byte [reg + 0], ch |
||
107 | adc byte [reg + 1], cl |
||
108 | rol ecx, 16 |
||
109 | adc byte [reg + 2], ch |
||
110 | adc byte [reg + 3], cl |
||
111 | |||
112 | } |
||
113 | |||
114 | |||
115 | |||
116 | |||
1196 | hidnplayr | 117 | ;----------------------------------------------------------------- |
118 | ; |
||
119 | ; TCP_init |
||
120 | ; |
||
121 | ; This function resets all TCP variables |
||
122 | ; |
||
123 | ; IN: / |
||
124 | ; OUT: / |
||
125 | ; |
||
126 | ;----------------------------------------------------------------- |
||
127 | |||
128 | align 4 |
||
129 | TCP_init: |
||
130 | |||
131 | xor eax, eax |
||
132 | mov edi, TCP_PACKETS_TX |
||
133 | mov ecx, 2*MAX_IP |
||
134 | rep stosd |
||
135 | |||
1249 | hidnplayr | 136 | init_queue TCP_IN_QUEUE |
137 | init_queue TCP_OUT_QUEUE |
||
1196 | hidnplayr | 138 | |
139 | ret |
||
140 | |||
141 | |||
142 | ;----------------------------------------------------------------- |
||
143 | ; |
||
1249 | hidnplayr | 144 | ; TCP_decrease_socket_ttls |
1159 | hidnplayr | 145 | ; |
1249 | hidnplayr | 146 | ; IN: / |
147 | ; OUT: / |
||
1159 | hidnplayr | 148 | ; |
1196 | hidnplayr | 149 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 150 | |
1196 | hidnplayr | 151 | align 4 |
1249 | hidnplayr | 152 | TCP_decrease_socket_ttls: |
1159 | hidnplayr | 153 | ; scan through all the sockets, decrementing active timers |
154 | |||
155 | mov ebx, net_sockets |
||
156 | |||
1249 | hidnplayr | 157 | cmp [ebx + SOCKET_head.NextPtr], 0 |
1159 | hidnplayr | 158 | je .exit |
159 | |||
160 | .next_socket: |
||
1249 | hidnplayr | 161 | mov ebx, [ebx + SOCKET_head.NextPtr] |
1159 | hidnplayr | 162 | or ebx, ebx |
163 | jz .exit |
||
164 | |||
1249 | hidnplayr | 165 | cmp [ebx + SOCKET_head.Type], IP_PROTO_TCP |
166 | jne .next_socket |
||
167 | |||
1196 | hidnplayr | 168 | ; DEBUGF 1, "K : %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState] |
1159 | hidnplayr | 169 | |
1249 | hidnplayr | 170 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], 0 |
1159 | hidnplayr | 171 | jne .decrement_tcb |
1249 | hidnplayr | 172 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0 |
1159 | hidnplayr | 173 | jne .decrement_wnd |
174 | jmp .next_socket |
||
175 | |||
176 | .decrement_tcb: |
||
177 | ; decrement it, delete socket if TCB timer = 0 & socket in timewait state |
||
1249 | hidnplayr | 178 | dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer] |
1159 | hidnplayr | 179 | jnz .next_socket |
180 | |||
1249 | hidnplayr | 181 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT |
1159 | hidnplayr | 182 | jne .next_socket |
183 | |||
1249 | hidnplayr | 184 | push [ebx + SOCKET_head.PrevPtr] |
1159 | hidnplayr | 185 | stdcall net_socket_free, ebx |
186 | pop ebx |
||
187 | jmp .next_socket |
||
188 | |||
189 | .decrement_wnd: |
||
190 | ; TODO - prove it works! |
||
1249 | hidnplayr | 191 | dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer] |
1159 | hidnplayr | 192 | jmp .next_socket |
193 | |||
194 | .exit: |
||
195 | ret |
||
196 | |||
197 | |||
1249 | hidnplayr | 198 | |
199 | ;----------------------------------------------------------------- |
||
1159 | hidnplayr | 200 | ; |
1249 | hidnplayr | 201 | ; TCP_send_queued: |
1159 | hidnplayr | 202 | ; |
1249 | hidnplayr | 203 | ; Decreases 'ttl' of tcp packets queued. |
204 | ; if 'ttl' reaches 0, resend the packet and decrease 'retries' |
||
205 | ; if 'retries' reaches zero, remove the queued packet |
||
206 | ; |
||
207 | ; IN: / |
||
208 | ; OUT: / |
||
209 | ; |
||
210 | ;----------------------------------------------------------------- |
||
1159 | hidnplayr | 211 | |
1196 | hidnplayr | 212 | align 4 |
1249 | hidnplayr | 213 | TCP_send_queued: |
1159 | hidnplayr | 214 | |
1249 | hidnplayr | 215 | cmp [TCP_OUT_QUEUE], 0 |
216 | je .exit |
||
1159 | hidnplayr | 217 | |
1249 | hidnplayr | 218 | mov eax, TCP_QUEUE_SIZE |
219 | mov ecx, [TCP_OUT_QUEUE] |
||
220 | mov esi, TCP_OUT_QUEUE+4 |
||
1159 | hidnplayr | 221 | |
1249 | hidnplayr | 222 | .loop: |
223 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
224 | jnz .found_one |
||
225 | add esi, tcp_out_queue_entry.size |
||
226 | loop .loop |
||
227 | .exit: |
||
228 | ret |
||
1159 | hidnplayr | 229 | |
1249 | hidnplayr | 230 | .found_one: |
231 | dec [esi + tcp_out_queue_entry.ttl] |
||
232 | jz .send_it |
||
233 | .find_next: |
||
234 | dec eax |
||
235 | jz .exit |
||
236 | jmp .loop |
||
1159 | hidnplayr | 237 | |
1249 | hidnplayr | 238 | .send_it: |
239 | push eax ecx esi |
||
1159 | hidnplayr | 240 | |
1249 | hidnplayr | 241 | push [esi + tcp_out_queue_entry.data_size] |
242 | push [esi + tcp_out_queue_entry.data_ptr] |
||
243 | mov ebx, [esi + tcp_out_queue_entry.owner] |
||
1159 | hidnplayr | 244 | |
1249 | hidnplayr | 245 | call [esi + tcp_out_queue_entry.sendproc] |
1159 | hidnplayr | 246 | |
1249 | hidnplayr | 247 | pop esi ecx eax |
1159 | hidnplayr | 248 | |
1249 | hidnplayr | 249 | dec [esi + tcp_out_queue_entry.retries] |
250 | jz .remove_it |
||
251 | mov [esi + tcp_out_queue_entry.ttl], TCP_TIMEOUT |
||
252 | jmp .find_next |
||
1159 | hidnplayr | 253 | |
1249 | hidnplayr | 254 | .remove_it: |
255 | push [esi + tcp_out_queue_entry.data_ptr] |
||
256 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
257 | dec [TCP_OUT_QUEUE] |
||
258 | call kernel_free |
||
259 | jmp .find_next |
||
1159 | hidnplayr | 260 | |
261 | |||
262 | |||
1249 | hidnplayr | 263 | ;----------------------------------------------------------------- |
264 | ; |
||
265 | ; TCP_add_to_queue: |
||
266 | ; |
||
267 | ; Queue a TCP packet for sending |
||
268 | ; |
||
269 | ; IN: [esp] pointer to buffer |
||
270 | ; [esp + 4] size of buffer |
||
271 | ; ebx = driver struct |
||
272 | ; esi = sender proc |
||
273 | ; edx = acknum |
||
274 | ; OUT: / |
||
275 | ; |
||
276 | ;----------------------------------------------------------------- |
||
1159 | hidnplayr | 277 | |
1249 | hidnplayr | 278 | align 4 |
279 | TCP_add_to_queue: |
||
1159 | hidnplayr | 280 | |
1249 | hidnplayr | 281 | cmp [TCP_OUT_QUEUE], TCP_QUEUE_SIZE |
282 | jge .full |
||
1159 | hidnplayr | 283 | |
1249 | hidnplayr | 284 | mov ecx, TCP_QUEUE_SIZE |
285 | mov eax, TCP_OUT_QUEUE+4 |
||
1159 | hidnplayr | 286 | |
1249 | hidnplayr | 287 | .loop: |
288 | cmp [eax + tcp_out_queue_entry.data_ptr], 0 |
||
289 | je .found_it |
||
290 | add eax, tcp_out_queue_entry.size |
||
291 | loop .loop |
||
1159 | hidnplayr | 292 | |
1249 | hidnplayr | 293 | .full: ; silently discard the packet |
294 | call kernel_free |
||
295 | add esp, 4 |
||
296 | |||
1159 | hidnplayr | 297 | ret |
298 | |||
1249 | hidnplayr | 299 | .found_it: ; eax point to empty queue entry |
1159 | hidnplayr | 300 | |
1249 | hidnplayr | 301 | pop [eax + tcp_out_queue_entry.data_ptr] |
302 | pop [eax + tcp_out_queue_entry.data_size] |
||
303 | mov [eax + tcp_out_queue_entry.ttl], 1 ; send immediately |
||
304 | mov [eax + tcp_out_queue_entry.retries], TCP_RETRIES |
||
305 | mov [eax + tcp_out_queue_entry.owner], ebx |
||
306 | mov [eax + tcp_out_queue_entry.sendproc], esi |
||
307 | mov [eax + tcp_out_queue_entry.ack_num], edx |
||
1196 | hidnplayr | 308 | |
1249 | hidnplayr | 309 | |
310 | ret |
||
311 | |||
312 | |||
1196 | hidnplayr | 313 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 314 | ; |
1249 | hidnplayr | 315 | ; TCP_handler: |
1159 | hidnplayr | 316 | ; |
1196 | hidnplayr | 317 | ; Called by IPv4_handler, |
318 | ; this procedure will inject the tcp data diagrams in the application sockets. |
||
319 | ; |
||
320 | ; IN: Pointer to buffer in [esp] |
||
321 | ; size of buffer in [esp+4] |
||
322 | ; pointer to device struct in ebx |
||
323 | ; TCP Packet size in ecx |
||
324 | ; pointer to TCP Packet data in edx |
||
325 | ; SourceAddres in esi |
||
326 | ; OUT: / |
||
327 | ; |
||
328 | ;----------------------------------------------------------------- |
||
1159 | hidnplayr | 329 | |
1249 | hidnplayr | 330 | align 4 |
331 | TCP_handler : |
||
1159 | hidnplayr | 332 | |
1196 | hidnplayr | 333 | DEBUGF 1,"TCP_Handler\n" |
334 | |||
1159 | hidnplayr | 335 | ; IP Packet TCP Destination Port = local Port |
1249 | hidnplayr | 336 | ; IP Packet SA = Remote IP OR = 0 |
337 | ; IP Packet TCP Source Port = remote Port OR = 0 |
||
1159 | hidnplayr | 338 | |
339 | mov ebx, net_sockets |
||
340 | |||
1249 | hidnplayr | 341 | .socket_loop: |
342 | mov ebx, [ebx + SOCKET_head.NextPtr] |
||
1159 | hidnplayr | 343 | or ebx, ebx |
1249 | hidnplayr | 344 | jz .dump |
1159 | hidnplayr | 345 | |
1249 | hidnplayr | 346 | mov ax, [edx + TCP_Packet.DestinationPort] |
347 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax |
||
348 | jne .socket_loop |
||
1159 | hidnplayr | 349 | |
1249 | hidnplayr | 350 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
351 | cmp eax, esi |
||
352 | je @f |
||
353 | test eax, eax |
||
354 | jne .socket_loop |
||
355 | @@: |
||
1159 | hidnplayr | 356 | |
1249 | hidnplayr | 357 | mov ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort] |
358 | cmp [edx + TCP_Packet.SourcePort] , ax |
||
359 | je .change_state |
||
360 | test ax, ax |
||
361 | jne .socket_loop |
||
1159 | hidnplayr | 362 | |
1249 | hidnplayr | 363 | .change_state: |
1159 | hidnplayr | 364 | |
1249 | hidnplayr | 365 | push ebx |
366 | lea ebx, [ebx + SOCKET_head.lock] |
||
367 | call wait_mutex |
||
368 | pop ebx |
||
1159 | hidnplayr | 369 | |
1249 | hidnplayr | 370 | ;---------------------------------- |
371 | ; ebx is pointer to socket |
||
372 | ; ecx is size of tcp packet |
||
373 | ; edx is pointer to tcp packet |
||
1159 | hidnplayr | 374 | |
1249 | hidnplayr | 375 | ; as a Packet has been received, update the TCB timer |
376 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], TWOMSL |
||
1159 | hidnplayr | 377 | |
1249 | hidnplayr | 378 | ; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges |
379 | test [edx + TCP_Packet.Flags], TH_ACK |
||
380 | jz .call_handler ; No ACK, so no data yet |
||
1159 | hidnplayr | 381 | |
1249 | hidnplayr | 382 | mov eax, [edx + TCP_Packet.SequenceNumber] ; Calculate sequencenumber in eax |
383 | bswap eax ; |
||
384 | add eax, ecx ; |
||
1159 | hidnplayr | 385 | |
1249 | hidnplayr | 386 | cmp [TCP_OUT_QUEUE], 0 |
387 | je .call_handler |
||
1159 | hidnplayr | 388 | |
1249 | hidnplayr | 389 | push ecx |
390 | mov ecx, TCP_QUEUE_SIZE |
||
391 | mov esi, TCP_OUT_QUEUE+4 |
||
1159 | hidnplayr | 392 | |
1249 | hidnplayr | 393 | .loop: |
394 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
395 | jne .maybe_next |
||
396 | cmp [esi + tcp_out_queue_entry.ack_num], eax |
||
397 | jg .maybe_next |
||
1159 | hidnplayr | 398 | |
1249 | hidnplayr | 399 | push [esi + tcp_out_queue_entry.data_ptr] |
400 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
401 | dec [TCP_OUT_QUEUE] |
||
402 | call kernel_free |
||
1159 | hidnplayr | 403 | |
1249 | hidnplayr | 404 | .maybe_next: |
405 | add esi, tcp_out_queue_entry.size |
||
406 | loop .loop |
||
407 | pop ecx |
||
1159 | hidnplayr | 408 | |
1249 | hidnplayr | 409 | .call_handler: |
410 | ; Call handler for given TCB state |
||
411 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState] |
||
412 | cmp eax, TCB_LISTEN |
||
413 | jb .exit |
||
414 | cmp eax, TCB_CLOSED |
||
415 | ja .exit |
||
1159 | hidnplayr | 416 | |
1249 | hidnplayr | 417 | shl eax, 2 |
418 | add eax, TCBStateHandler - 4 |
||
1159 | hidnplayr | 419 | |
1249 | hidnplayr | 420 | push .exit |
421 | jmp eax |
||
1159 | hidnplayr | 422 | |
423 | .exit: |
||
1249 | hidnplayr | 424 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 425 | |
1249 | hidnplayr | 426 | .dump: |
427 | DEBUGF 1,"Dumping TCP packet\n" |
||
1196 | hidnplayr | 428 | call kernel_free |
429 | add esp, 4 ; pop (balance stack) |
||
1159 | hidnplayr | 430 | |
1249 | hidnplayr | 431 | ret |
1196 | hidnplayr | 432 | |
433 | |||
434 | |||
435 | ;----------------------------------------------------------------- |
||
436 | ; |
||
1249 | hidnplayr | 437 | ; TCP_socket_send |
1196 | hidnplayr | 438 | ; |
1249 | hidnplayr | 439 | ; IN: eax = socket pointer |
440 | ; ecx = number of bytes to send |
||
441 | ; esi = pointer to data |
||
442 | ; |
||
1196 | hidnplayr | 443 | ;----------------------------------------------------------------- |
444 | |||
1249 | hidnplayr | 445 | align 4 |
446 | TCP_socket_send: |
||
1196 | hidnplayr | 447 | |
1249 | hidnplayr | 448 | DEBUGF 1,"Creating TCP Packet\n" |
1159 | hidnplayr | 449 | |
1249 | hidnplayr | 450 | mov di , IP_PROTO_TCP |
1159 | hidnplayr | 451 | |
1249 | hidnplayr | 452 | ; Create an IPv4 Packet of the correct size |
453 | push eax |
||
454 | mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
||
455 | mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
1159 | hidnplayr | 456 | |
1249 | hidnplayr | 457 | ; meanwhile, create the pseudoheader in stack, |
458 | ; (now that we still have all the variables that are needed.) |
||
459 | push cx |
||
460 | push di |
||
1159 | hidnplayr | 461 | push eax |
1249 | hidnplayr | 462 | push ebx |
1159 | hidnplayr | 463 | |
464 | |||
1249 | hidnplayr | 465 | push ecx esi eax ; save some variables for later |
466 | add ecx, TCP_Packet.Data |
||
467 | call IPv4_create_packet |
||
468 | cmp edi, -1 |
||
469 | je .fail |
||
1159 | hidnplayr | 470 | |
1249 | hidnplayr | 471 | pop esi |
1159 | hidnplayr | 472 | |
1249 | hidnplayr | 473 | ; Now add the TCP header to the IPv4 packet |
1159 | hidnplayr | 474 | |
1249 | hidnplayr | 475 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
476 | pop [edi + TCP_Packet.SequenceNumber] |
||
1159 | hidnplayr | 477 | |
1249 | hidnplayr | 478 | push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] |
479 | pop dword [edi + TCP_Packet.SourcePort] |
||
1159 | hidnplayr | 480 | |
481 | |||
1249 | hidnplayr | 482 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
483 | pop [edi + TCP_Packet.AckNumber] |
||
1159 | hidnplayr | 484 | |
1249 | hidnplayr | 485 | mov al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags] |
486 | mov [edi + TCP_Packet.Flags], al |
||
1159 | hidnplayr | 487 | |
1249 | hidnplayr | 488 | mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes ;;; TODO: read RFC ! |
489 | mov [edi + TCP_Packet.UrgentPointer], 0 |
||
490 | mov [edi + TCP_Packet.DataOffset], 0x50 |
||
491 | mov [edi + TCP_Packet.Checksum], 0 |
||
1159 | hidnplayr | 492 | |
1249 | hidnplayr | 493 | ; Copy the data |
494 | mov esi, [esp] |
||
495 | mov ecx, [esp+4] |
||
496 | add edi, TCP_Packet.Data |
||
1159 | hidnplayr | 497 | |
1249 | hidnplayr | 498 | shr ecx, 1 |
499 | jnc .nb |
||
500 | movsb |
||
501 | .nb: shr ecx, 1 |
||
502 | jnc .nw |
||
503 | movsw |
||
504 | .nw: rep movsd |
||
1159 | hidnplayr | 505 | |
1249 | hidnplayr | 506 | ; Now, calculate the checksum for pseudoheader |
507 | xor edx, edx |
||
508 | mov ecx, 12 |
||
509 | mov esi, esp |
||
510 | call checksum_1 |
||
511 | add esp, 12 ; remove the pseudoheader from stack |
||
512 | ; And that of the data |
||
513 | pop esi |
||
514 | pop ecx |
||
515 | call checksum_1 |
||
516 | ; Now create the final checksum and store it in TCP header |
||
517 | call checksum_2 |
||
518 | mov [edi + TCP_Packet.Checksum], dx |
||
1159 | hidnplayr | 519 | |
1249 | hidnplayr | 520 | ; And now, send it! |
521 | DEBUGF 1,"Sending TCP Packet to device %x\n", ebx |
||
522 | mov esi, ETH_sender |
||
523 | mov edx, [edi + TCP_Packet.AckNumber] |
||
524 | jmp TCP_add_to_queue |
||
1159 | hidnplayr | 525 | |
1249 | hidnplayr | 526 | .fail: |
527 | add esp, 12+4 |
||
1159 | hidnplayr | 528 | ret |
529 | |||
530 | |||
531 | |||
532 | |||
533 | |||
1249 | hidnplayr | 534 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 535 | ; |
1249 | hidnplayr | 536 | ; TCP_send_ack |
1159 | hidnplayr | 537 | ; |
1249 | hidnplayr | 538 | ; IN: eax = socket pointer |
539 | ; bl = flags |
||
1159 | hidnplayr | 540 | ; |
1249 | hidnplayr | 541 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 542 | |
1249 | hidnplayr | 543 | align 4 |
544 | TCP_send_ack: |
||
1159 | hidnplayr | 545 | |
1249 | hidnplayr | 546 | DEBUGF 1,"Creating TCP ACK\n" |
1159 | hidnplayr | 547 | |
1249 | hidnplayr | 548 | mov di , IP_PROTO_TCP |
549 | mov cx , TCP_Packet.Data |
||
1159 | hidnplayr | 550 | |
1249 | hidnplayr | 551 | push bx eax |
1159 | hidnplayr | 552 | |
1249 | hidnplayr | 553 | ; Create an IPv4 Packet of the correct size |
554 | mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
||
555 | mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
1159 | hidnplayr | 556 | |
1249 | hidnplayr | 557 | call IPv4_create_packet |
558 | cmp edi, -1 |
||
559 | je .fail |
||
1159 | hidnplayr | 560 | |
1249 | hidnplayr | 561 | ; Fill in the TCP header |
562 | pop esi |
||
1159 | hidnplayr | 563 | |
1249 | hidnplayr | 564 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
565 | pop [edi + TCP_Packet.SequenceNumber] |
||
1159 | hidnplayr | 566 | |
1249 | hidnplayr | 567 | push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] |
568 | pop dword [edi + TCP_Packet.SourcePort] |
||
1159 | hidnplayr | 569 | |
1249 | hidnplayr | 570 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
571 | pop [edi + TCP_Packet.AckNumber] |
||
1159 | hidnplayr | 572 | |
1249 | hidnplayr | 573 | pop cx |
574 | mov [edi + TCP_Packet.Flags], cl |
||
575 | mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes |
||
576 | mov [edi + TCP_Packet.UrgentPointer], 0 |
||
577 | mov [edi + TCP_Packet.DataOffset], 0x50 |
||
1159 | hidnplayr | 578 | |
1249 | hidnplayr | 579 | push eax edx |
1159 | hidnplayr | 580 | |
1249 | hidnplayr | 581 | push word TCP_Packet.Data shl 8 |
582 | push IP_PROTO_TCP |
||
583 | push [esi + SOCKET_head.end + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
584 | push [esi + SOCKET_head.end + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
||
1159 | hidnplayr | 585 | |
1249 | hidnplayr | 586 | ; Now, calculate the checksum for pseudoheader |
587 | xor edx, edx |
||
588 | mov ecx, 12 |
||
589 | mov esi, esp |
||
590 | call checksum_1 |
||
591 | add esp, 12 ; remove the pseudoheader from stack |
||
592 | ; Now create the final checksum and store it in TCP header |
||
593 | call checksum_2 |
||
594 | mov [edi + TCP_Packet.Checksum], dx |
||
1159 | hidnplayr | 595 | |
1249 | hidnplayr | 596 | ; And now, send it! |
597 | DEBUGF 1,"Sending TCP Packet to device %x\n", ebx |
||
598 | mov esi, ETH_sender |
||
599 | mov edx, [edi + TCP_Packet.AckNumber] |
||
600 | jmp TCP_add_to_queue |
||
1159 | hidnplayr | 601 | |
1249 | hidnplayr | 602 | .fail: |
603 | add esp, 12+4 |
||
604 | ret |
||
1159 | hidnplayr | 605 | |
606 | |||
607 | |||
608 | |||
609 | |||
1249 | hidnplayr | 610 | align 4 |
611 | stateTCB_LISTEN: |
||
1159 | hidnplayr | 612 | ; In this case, we are expecting a SYN Packet |
613 | ; For now, if the Packet is a SYN, process it, and send a response |
||
614 | ; If not, ignore it |
||
615 | |||
616 | ; Look at control flags |
||
1249 | hidnplayr | 617 | test [edx + TCP_Packet.Flags], TH_SYN |
1159 | hidnplayr | 618 | jz .exit |
619 | |||
620 | ; We have a SYN. update the socket with this IP Packets details, |
||
621 | ; And send a response |
||
622 | |||
1249 | hidnplayr | 623 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address |
624 | mov ax, [edx + TCP_Packet.SourcePort] |
||
625 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax |
||
626 | mov eax, [edx + TCP_Packet.SequenceNumber] |
||
627 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax |
||
628 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax |
||
629 | lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
||
630 | inc_INET esi ; RCV.NXT |
||
631 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS] |
||
632 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax |
||
1159 | hidnplayr | 633 | |
1249 | hidnplayr | 634 | ; Now construct the response |
1159 | hidnplayr | 635 | mov bl, TH_SYN + TH_ACK |
1249 | hidnplayr | 636 | call TCP_send_ack |
1159 | hidnplayr | 637 | |
1249 | hidnplayr | 638 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED |
1159 | hidnplayr | 639 | |
640 | ; increment SND.NXT in socket |
||
1249 | hidnplayr | 641 | lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
642 | inc_INET esi |
||
1159 | hidnplayr | 643 | |
644 | .exit: |
||
645 | ret |
||
646 | |||
647 | |||
1249 | hidnplayr | 648 | align 4 |
649 | stateTCB_SYN_SENT: |
||
1159 | hidnplayr | 650 | ; We are awaiting an ACK to our SYN, with a SYM |
651 | ; Look at control flags - expecting an ACK |
||
652 | |||
1249 | hidnplayr | 653 | mov al, [edx + TCP_Packet.Flags] |
1159 | hidnplayr | 654 | and al, TH_SYN + TH_ACK |
655 | cmp al, TH_SYN + TH_ACK |
||
656 | je .syn_ack |
||
657 | |||
658 | test al, TH_SYN |
||
659 | jz .exit |
||
660 | |||
1249 | hidnplayr | 661 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED |
1159 | hidnplayr | 662 | push TH_SYN + TH_ACK |
663 | jmp .send |
||
664 | |||
665 | .syn_ack: |
||
1249 | hidnplayr | 666 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED |
1159 | hidnplayr | 667 | push TH_ACK |
668 | |||
669 | .send: |
||
670 | ; Store the recv.nxt field |
||
1249 | hidnplayr | 671 | mov eax, [edx + TCP_Packet.SequenceNumber] |
1159 | hidnplayr | 672 | |
673 | ; Update our recv.nxt field |
||
1249 | hidnplayr | 674 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax |
675 | lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
||
676 | inc_INET esi |
||
1159 | hidnplayr | 677 | |
678 | ; Send an ACK |
||
679 | pop ebx |
||
1249 | hidnplayr | 680 | call TCP_send_ack |
1159 | hidnplayr | 681 | |
682 | .exit: |
||
683 | ret |
||
684 | |||
685 | |||
1249 | hidnplayr | 686 | |
687 | align 4 |
||
688 | stateTCB_SYN_RECEIVED: |
||
1159 | hidnplayr | 689 | ; In this case, we are expecting an ACK Packet |
690 | ; For now, if the Packet is an ACK, process it, |
||
691 | ; If not, ignore it |
||
692 | |||
1249 | hidnplayr | 693 | test [edx + TCP_Packet.Flags], TH_RST |
1159 | hidnplayr | 694 | jz .check_ack |
695 | |||
1249 | hidnplayr | 696 | push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort] |
697 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort] |
||
698 | push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP] |
||
699 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
1159 | hidnplayr | 700 | |
1249 | hidnplayr | 701 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_LISTEN |
1159 | hidnplayr | 702 | jmp .exit |
703 | |||
704 | .check_ack: |
||
705 | ; Look at control flags - expecting an ACK |
||
1249 | hidnplayr | 706 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 707 | jz .exit |
708 | |||
1249 | hidnplayr | 709 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED |
1159 | hidnplayr | 710 | |
711 | .exit: |
||
712 | ret |
||
713 | |||
714 | |||
1249 | hidnplayr | 715 | |
716 | align 4 |
||
717 | stateTCB_ESTABLISHED: |
||
1159 | hidnplayr | 718 | ; Here we are expecting data, or a request to close |
719 | ; OR both... |
||
720 | |||
721 | ; Did we receive a FIN or RST? |
||
1249 | hidnplayr | 722 | test [edx + TCP_Packet.Flags], TH_FIN |
1159 | hidnplayr | 723 | jz .check_ack |
724 | |||
725 | ; It was a fin or reset. |
||
726 | |||
727 | ; Remove resend entries from the queue - I dont want to send any more data |
||
1249 | hidnplayr | 728 | ; Send an ACK to that fin, and enter closewait state |
1159 | hidnplayr | 729 | |
730 | .check_ack: |
||
731 | ; Check that we received an ACK |
||
1249 | hidnplayr | 732 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 733 | jz .exit |
734 | |||
735 | ; First, look at the incoming window. If this is less than or equal to 1024, |
||
736 | ; Set the socket window timer to 1. This will stop an additional Packets being queued. |
||
737 | ; ** I may need to tweak this value, since I do not know how many Packets are already queued |
||
1249 | hidnplayr | 738 | mov cx, [edx + TCP_Packet.Window] |
1159 | hidnplayr | 739 | xchg cl, ch |
740 | cmp cx, 1024 |
||
741 | ja @f |
||
742 | |||
1249 | hidnplayr | 743 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1 |
1159 | hidnplayr | 744 | |
745 | @@: ; OK, here is the deal |
||
746 | ; My recv.nct field holds the seq of the expected next rec byte |
||
747 | ; if the recevied sequence number is not equal to this, do not |
||
748 | ; increment the recv.nxt field, do not copy data - just send a |
||
749 | ; repeat ack. |
||
750 | |||
751 | ; recv.nxt is in dword [edx+24], in inet format |
||
752 | ; recv seq is in [sktAddr]+56, in inet format |
||
753 | ; just do a comparision |
||
1249 | hidnplayr | 754 | mov ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
755 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSE_WAIT |
||
1159 | hidnplayr | 756 | jne @f |
757 | mov ecx, eax |
||
758 | |||
1249 | hidnplayr | 759 | @@: cmp ecx, [edx + TCP_Packet.SequenceNumber] |
1159 | hidnplayr | 760 | jne .ack |
761 | |||
1249 | hidnplayr | 762 | test ecx, ecx |
763 | jnz .data |
||
1159 | hidnplayr | 764 | |
765 | ; If we had received a fin, we need to ACK it. |
||
1249 | hidnplayr | 766 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSE_WAIT |
1159 | hidnplayr | 767 | je .ack |
768 | jmp .exit |
||
769 | |||
770 | .data: |
||
1249 | hidnplayr | 771 | mov esi, [esp + 4] |
772 | sub edx, esi |
||
773 | mov edi, edx |
||
774 | call socket_internal_receiver |
||
1159 | hidnplayr | 775 | |
776 | .ack: |
||
777 | ; Send an ACK |
||
778 | mov bl, TH_ACK |
||
1249 | hidnplayr | 779 | call TCP_send_ack |
1159 | hidnplayr | 780 | .exit: |
781 | ret |
||
782 | |||
783 | |||
1249 | hidnplayr | 784 | |
785 | align 4 |
||
786 | stateTCB_FIN_WAIT_1: |
||
1159 | hidnplayr | 787 | ; We can either receive an ACK of a fin, or a fin |
1249 | hidnplayr | 788 | mov al, [edx + TCP_Packet.Flags] |
1159 | hidnplayr | 789 | and al, TH_FIN + TH_ACK |
790 | |||
791 | cmp al, TH_ACK |
||
792 | jne @f |
||
793 | |||
794 | ; It was an ACK |
||
1249 | hidnplayr | 795 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_FIN_WAIT_2 |
1159 | hidnplayr | 796 | jmp .exit |
797 | |||
1249 | hidnplayr | 798 | @@: mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSING |
1159 | hidnplayr | 799 | cmp al, TH_FIN |
800 | je @f |
||
1249 | hidnplayr | 801 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT |
1159 | hidnplayr | 802 | |
1249 | hidnplayr | 803 | @@: lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
804 | inc_INET esi |
||
1159 | hidnplayr | 805 | ; Send an ACK |
806 | mov bl, TH_ACK |
||
1249 | hidnplayr | 807 | call TCP_send_ack |
1159 | hidnplayr | 808 | |
809 | .exit: |
||
810 | ret |
||
811 | |||
812 | |||
1249 | hidnplayr | 813 | |
814 | align 4 |
||
815 | stateTCB_FIN_WAIT_2: |
||
816 | test [edx + TCP_Packet.Flags], TH_FIN |
||
1159 | hidnplayr | 817 | jz .exit |
818 | |||
819 | ; Change state, as we have a fin |
||
1249 | hidnplayr | 820 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT |
1159 | hidnplayr | 821 | |
1249 | hidnplayr | 822 | lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
823 | inc_INET esi |
||
1159 | hidnplayr | 824 | |
825 | ; Send an ACK |
||
826 | mov bl, TH_ACK |
||
1249 | hidnplayr | 827 | call TCP_send_ack |
1159 | hidnplayr | 828 | |
829 | .exit: |
||
830 | ret |
||
831 | |||
832 | |||
1249 | hidnplayr | 833 | |
834 | align 4 |
||
835 | stateTCB_CLOSE_WAIT: |
||
1159 | hidnplayr | 836 | ; Intentionally left empty |
837 | ; socket_close_tcp handles this |
||
838 | ret |
||
839 | |||
840 | |||
1249 | hidnplayr | 841 | |
842 | align 4 |
||
843 | stateTCB_CLOSING: |
||
1159 | hidnplayr | 844 | ; We can either receive an ACK of a fin, or a fin |
1249 | hidnplayr | 845 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 846 | jz .exit |
847 | |||
1249 | hidnplayr | 848 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT |
1159 | hidnplayr | 849 | |
850 | .exit: |
||
851 | ret |
||
852 | |||
853 | |||
1249 | hidnplayr | 854 | align 4 |
855 | stateTCB_LAST_ACK: |
||
1159 | hidnplayr | 856 | ; Look at control flags - expecting an ACK |
1249 | hidnplayr | 857 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 858 | jz .exit |
859 | |||
860 | ; delete the socket |
||
861 | stdcall net_socket_free, ebx |
||
862 | |||
863 | .exit: |
||
864 | ret |
||
865 | |||
866 | |||
1249 | hidnplayr | 867 | align 4 |
868 | stateTCB_TIME_WAIT: |
||
1159 | hidnplayr | 869 | ret |
870 | |||
871 | |||
1249 | hidnplayr | 872 | align 4 |
873 | stateTCB_CLOSED: |
||
1159 | hidnplayr | 874 | ret |
875 |