Rev 1318 | 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 ;; |
||
1318 | hidnplayr | 11 | ;; Inspired by the TCP code of Mike Hibbit for MenuetOS ;; |
1196 | hidnplayr | 12 | ;; ;; |
13 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
14 | ;; Version 2, June 1991 ;; |
||
15 | ;; ;; |
||
16 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
1159 | hidnplayr | 17 | |
1196 | hidnplayr | 18 | |
1206 | hidnplayr | 19 | $Revision: 1473 $ |
1159 | hidnplayr | 20 | |
1196 | hidnplayr | 21 | TCP_RETRIES equ 5 ; Number of times to resend a Packet |
1254 | hidnplayr | 22 | TCP_PACKET_TTL equ 50 ; resend if not replied to in 1/100 s |
23 | TCP_SOCKET_TTL equ 10 ; # of secs to wait before closing socket |
||
1196 | hidnplayr | 24 | TCP_QUEUE_SIZE equ 16 |
25 | |||
1318 | hidnplayr | 26 | TCP_MAX_ACKS equ 16 |
1249 | hidnplayr | 27 | |
1318 | hidnplayr | 28 | |
1159 | hidnplayr | 29 | struct TCP_Packet |
30 | .SourcePort dw ? |
||
31 | .DestinationPort dw ? |
||
32 | .SequenceNumber dd ? |
||
33 | .AckNumber dd ? |
||
1196 | hidnplayr | 34 | .DataOffset db ? ; DataOffset[0-3 bits] and Reserved[4-7] |
35 | .Flags db ? ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN |
||
1159 | hidnplayr | 36 | .Window dw ? |
37 | .Checksum dw ? |
||
38 | .UrgentPointer dw ? |
||
1274 | hidnplayr | 39 | ; .Options rb 3 |
40 | ; .Padding db ? |
||
1159 | hidnplayr | 41 | .Data: |
42 | ends |
||
43 | |||
1274 | hidnplayr | 44 | struct tcp_in_queue_entry |
45 | .data_ptr dd ? |
||
46 | .data_size dd ? |
||
1281 | hidnplayr | 47 | .offset dd ? ; TODO: replace this in code by absolute address isntead of relative offset |
1274 | hidnplayr | 48 | .size: |
49 | ends |
||
50 | |||
51 | struct tcp_out_queue_entry |
||
52 | .data_ptr dd ? |
||
53 | .data_size dd ? |
||
54 | .ttl dd ? |
||
55 | .retries dd ? |
||
56 | .owner dd ? |
||
57 | .sendproc dd ? |
||
58 | .seq_num dd ? |
||
59 | .socket dd ? |
||
60 | .size: |
||
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 |
1318 | hidnplayr | 69 | TCP_OUT_QUEUE dd ?, ? |
1249 | hidnplayr | 70 | rd (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4 |
1318 | hidnplayr | 71 | |
72 | TCP_ACKS dd ? |
||
73 | TCP_ACK_LIST rd 3*TCP_MAX_ACKS |
||
1196 | hidnplayr | 74 | endg |
75 | |||
1249 | hidnplayr | 76 | align 4 |
77 | iglobal |
||
1318 | hidnplayr | 78 | TCPstateHandler: |
1196 | hidnplayr | 79 | |
1249 | hidnplayr | 80 | dd stateTCB_LISTEN |
81 | dd stateTCB_SYN_SENT |
||
82 | dd stateTCB_SYN_RECEIVED |
||
83 | dd stateTCB_ESTABLISHED |
||
84 | dd stateTCB_FIN_WAIT_1 |
||
85 | dd stateTCB_FIN_WAIT_2 |
||
86 | dd stateTCB_CLOSE_WAIT |
||
87 | dd stateTCB_CLOSING |
||
88 | dd stateTCB_LAST_ACK |
||
89 | dd stateTCB_TIME_WAIT |
||
90 | dd stateTCB_CLOSED |
||
1196 | hidnplayr | 91 | |
1249 | hidnplayr | 92 | endg |
1196 | hidnplayr | 93 | |
1249 | hidnplayr | 94 | |
1196 | hidnplayr | 95 | ;----------------------------------------------------------------- |
96 | ; |
||
97 | ; TCP_init |
||
98 | ; |
||
99 | ; This function resets all TCP variables |
||
100 | ; |
||
101 | ; IN: / |
||
102 | ; OUT: / |
||
103 | ; |
||
104 | ;----------------------------------------------------------------- |
||
105 | align 4 |
||
106 | TCP_init: |
||
107 | |||
108 | xor eax, eax |
||
109 | mov edi, TCP_PACKETS_TX |
||
110 | mov ecx, 2*MAX_IP |
||
111 | rep stosd |
||
112 | |||
1249 | hidnplayr | 113 | init_queue TCP_IN_QUEUE |
1196 | hidnplayr | 114 | |
1274 | hidnplayr | 115 | ; tcp_out_queue is a special type of queue: |
116 | ; The first dword is a counter of total packets queued. |
||
117 | ; The remaining bytes are socket 'slots' wich use tcp_out_queue_entry data structure. |
||
118 | ; An empty slot is know by the fact that tcp_out_queue_entry.data_ptr (first dword of the slot) is set to 0 |
||
119 | ; There are TCP_OUT_QUEUE_SIZE number of slots |
||
1257 | hidnplayr | 120 | |
1254 | hidnplayr | 121 | xor eax, eax |
122 | mov esi, TCP_OUT_QUEUE |
||
1318 | hidnplayr | 123 | mov ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+2+2+3*TCP_MAX_ACKS |
1254 | hidnplayr | 124 | rep stosd |
125 | |||
1196 | hidnplayr | 126 | ret |
127 | |||
128 | |||
129 | ;----------------------------------------------------------------- |
||
130 | ; |
||
1249 | hidnplayr | 131 | ; TCP_decrease_socket_ttls |
1159 | hidnplayr | 132 | ; |
1249 | hidnplayr | 133 | ; IN: / |
134 | ; OUT: / |
||
1159 | hidnplayr | 135 | ; |
1196 | hidnplayr | 136 | ;----------------------------------------------------------------- |
137 | align 4 |
||
1249 | hidnplayr | 138 | TCP_decrease_socket_ttls: |
1274 | hidnplayr | 139 | ; scan through all the sockets, decrementing active timers |
1159 | hidnplayr | 140 | |
141 | mov ebx, net_sockets |
||
1249 | hidnplayr | 142 | cmp [ebx + SOCKET_head.NextPtr], 0 |
1159 | hidnplayr | 143 | je .exit |
144 | .next_socket: |
||
1249 | hidnplayr | 145 | mov ebx, [ebx + SOCKET_head.NextPtr] |
1159 | hidnplayr | 146 | or ebx, ebx |
147 | jz .exit |
||
148 | |||
1249 | hidnplayr | 149 | cmp [ebx + SOCKET_head.Type], IP_PROTO_TCP |
150 | jne .next_socket |
||
151 | |||
1254 | hidnplayr | 152 | ; 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.state] |
1159 | hidnplayr | 153 | |
1254 | hidnplayr | 154 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0 |
1159 | hidnplayr | 155 | jne .decrement_tcb |
1249 | hidnplayr | 156 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0 |
1159 | hidnplayr | 157 | jne .decrement_wnd |
158 | jmp .next_socket |
||
159 | |||
160 | .decrement_tcb: |
||
1274 | hidnplayr | 161 | ; decrement it, delete socket if TCB timer = 0 & socket in timewait state |
1254 | hidnplayr | 162 | dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer] |
1159 | hidnplayr | 163 | jnz .next_socket |
164 | |||
1254 | hidnplayr | 165 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT |
1159 | hidnplayr | 166 | jne .next_socket |
167 | |||
1249 | hidnplayr | 168 | push [ebx + SOCKET_head.PrevPtr] |
1159 | hidnplayr | 169 | stdcall net_socket_free, ebx |
170 | pop ebx |
||
171 | jmp .next_socket |
||
172 | |||
173 | .decrement_wnd: |
||
1249 | hidnplayr | 174 | dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer] |
1159 | hidnplayr | 175 | jmp .next_socket |
176 | |||
177 | .exit: |
||
178 | ret |
||
179 | |||
180 | |||
1249 | hidnplayr | 181 | |
182 | ;----------------------------------------------------------------- |
||
1159 | hidnplayr | 183 | ; |
1249 | hidnplayr | 184 | ; TCP_send_queued: |
1159 | hidnplayr | 185 | ; |
1249 | hidnplayr | 186 | ; Decreases 'ttl' of tcp packets queued. |
187 | ; if 'ttl' reaches 0, resend the packet and decrease 'retries' |
||
188 | ; if 'retries' reaches zero, remove the queued packet |
||
189 | ; |
||
190 | ; IN: / |
||
191 | ; OUT: / |
||
192 | ; |
||
193 | ;----------------------------------------------------------------- |
||
1196 | hidnplayr | 194 | align 4 |
1249 | hidnplayr | 195 | TCP_send_queued: |
1159 | hidnplayr | 196 | |
1249 | hidnplayr | 197 | cmp [TCP_OUT_QUEUE], 0 |
198 | je .exit |
||
1159 | hidnplayr | 199 | |
1318 | hidnplayr | 200 | mov ebx, TCP_OUT_QUEUE+4 |
201 | call wait_mutex |
||
202 | |||
1249 | hidnplayr | 203 | mov eax, TCP_QUEUE_SIZE |
204 | mov ecx, [TCP_OUT_QUEUE] |
||
1318 | hidnplayr | 205 | mov esi, TCP_OUT_QUEUE+8 |
1159 | hidnplayr | 206 | |
1249 | hidnplayr | 207 | .loop: |
208 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
209 | jnz .found_one |
||
210 | add esi, tcp_out_queue_entry.size |
||
211 | loop .loop |
||
212 | .exit: |
||
1318 | hidnplayr | 213 | mov [TCP_OUT_QUEUE+4], 0 |
1249 | hidnplayr | 214 | ret |
1159 | hidnplayr | 215 | |
1249 | hidnplayr | 216 | .found_one: |
217 | dec [esi + tcp_out_queue_entry.ttl] |
||
218 | jz .send_it |
||
1318 | hidnplayr | 219 | cmp [esi + tcp_out_queue_entry.data_ptr], -1 |
220 | jz .is_ack |
||
1249 | hidnplayr | 221 | .find_next: |
1254 | hidnplayr | 222 | add esi, tcp_out_queue_entry.size |
1249 | hidnplayr | 223 | dec eax |
224 | jz .exit |
||
1254 | hidnplayr | 225 | test ecx, ecx |
226 | jnz .loop |
||
1318 | hidnplayr | 227 | mov [TCP_OUT_QUEUE+4], 0 |
1254 | hidnplayr | 228 | ret |
1159 | hidnplayr | 229 | |
1249 | hidnplayr | 230 | .send_it: |
1318 | hidnplayr | 231 | pusha |
1254 | hidnplayr | 232 | mov ebx, [esi + tcp_out_queue_entry.owner] |
1318 | hidnplayr | 233 | pushd [esi + tcp_out_queue_entry.data_size] |
234 | pushd [esi + tcp_out_queue_entry.data_ptr] |
||
1254 | hidnplayr | 235 | DEBUGF 1,"Now sending TCP packet %x, size: %u, owner: %x, sendproc %x\n", [esp], [esp+4], ebx, [esi + tcp_out_queue_entry.sendproc] |
1257 | hidnplayr | 236 | inc [TCP_PACKETS_TX] |
1249 | hidnplayr | 237 | call [esi + tcp_out_queue_entry.sendproc] |
1254 | hidnplayr | 238 | add esp, 8 |
1318 | hidnplayr | 239 | popa |
1159 | hidnplayr | 240 | |
1249 | hidnplayr | 241 | dec [esi + tcp_out_queue_entry.retries] |
242 | jz .remove_it |
||
1254 | hidnplayr | 243 | |
244 | mov [esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL |
||
1249 | hidnplayr | 245 | jmp .find_next |
1159 | hidnplayr | 246 | |
1249 | hidnplayr | 247 | .remove_it: |
248 | push [esi + tcp_out_queue_entry.data_ptr] |
||
249 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
250 | call kernel_free |
||
1281 | hidnplayr | 251 | dec [TCP_OUT_QUEUE] |
1249 | hidnplayr | 252 | jmp .find_next |
1159 | hidnplayr | 253 | |
1318 | hidnplayr | 254 | .is_ack: |
255 | pusha |
||
256 | mov eax, [esi + tcp_out_queue_entry.socket] |
||
257 | mov ebx, [esi + tcp_out_queue_entry.owner] |
||
258 | mov ecx, [esi + tcp_out_queue_entry.size] |
||
259 | call TCP_send_ack |
||
260 | popa |
||
261 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
262 | dec [TCP_OUT_QUEUE] |
||
263 | jmp .find_next |
||
1159 | hidnplayr | 264 | |
265 | |||
1318 | hidnplayr | 266 | |
1249 | hidnplayr | 267 | ;----------------------------------------------------------------- |
268 | ; |
||
269 | ; TCP_handler: |
||
1159 | hidnplayr | 270 | ; |
1196 | hidnplayr | 271 | ; Called by IPv4_handler, |
272 | ; this procedure will inject the tcp data diagrams in the application sockets. |
||
273 | ; |
||
274 | ; IN: Pointer to buffer in [esp] |
||
275 | ; size of buffer in [esp+4] |
||
276 | ; pointer to device struct in ebx |
||
277 | ; TCP Packet size in ecx |
||
1274 | hidnplayr | 278 | ; pointer to TCP Packet in edx |
279 | ; SourceAddres (IPv4) in esi |
||
1196 | hidnplayr | 280 | ; OUT: / |
281 | ; |
||
282 | ;----------------------------------------------------------------- |
||
1249 | hidnplayr | 283 | align 4 |
284 | TCP_handler : |
||
1159 | hidnplayr | 285 | |
1196 | hidnplayr | 286 | DEBUGF 1,"TCP_Handler\n" |
287 | |||
1274 | hidnplayr | 288 | ; TODO: validate checksum |
1254 | hidnplayr | 289 | |
1318 | hidnplayr | 290 | ; Find a matching socket for received packet, all following expressions must be valid: |
291 | ; |
||
1274 | hidnplayr | 292 | ; IP Packet TCP Destination Port = local Port |
1318 | hidnplayr | 293 | ; (IP Packet SA = Remote IP) OR (Remote IP = 0) |
294 | ; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0) |
||
1159 | hidnplayr | 295 | |
296 | mov ebx, net_sockets |
||
297 | |||
1249 | hidnplayr | 298 | .socket_loop: |
299 | mov ebx, [ebx + SOCKET_head.NextPtr] |
||
1159 | hidnplayr | 300 | or ebx, ebx |
1249 | hidnplayr | 301 | jz .dump |
1159 | hidnplayr | 302 | |
1249 | hidnplayr | 303 | mov ax, [edx + TCP_Packet.DestinationPort] |
304 | cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax |
||
305 | jne .socket_loop |
||
1159 | hidnplayr | 306 | |
1249 | hidnplayr | 307 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
308 | cmp eax, esi |
||
309 | je @f |
||
310 | test eax, eax |
||
311 | jne .socket_loop |
||
312 | @@: |
||
1159 | hidnplayr | 313 | |
1249 | hidnplayr | 314 | mov ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort] |
315 | cmp [edx + TCP_Packet.SourcePort] , ax |
||
1274 | hidnplayr | 316 | je .found_socket |
1249 | hidnplayr | 317 | test ax, ax |
1254 | hidnplayr | 318 | jnz .socket_loop |
1274 | hidnplayr | 319 | .found_socket: |
1254 | hidnplayr | 320 | DEBUGF 1,"Found valid socket for packet\n" |
321 | |||
1257 | hidnplayr | 322 | inc [TCP_PACKETS_RX] |
323 | |||
1274 | hidnplayr | 324 | add ebx, SOCKET_head.lock |
1249 | hidnplayr | 325 | call wait_mutex |
1274 | hidnplayr | 326 | sub ebx, SOCKET_head.lock |
1159 | hidnplayr | 327 | |
1274 | hidnplayr | 328 | ;------------------------------- |
1249 | hidnplayr | 329 | ; ebx is pointer to socket |
330 | ; ecx is size of tcp packet |
||
331 | ; edx is pointer to tcp packet |
||
1159 | hidnplayr | 332 | |
1274 | hidnplayr | 333 | ; calculate header length |
334 | movzx eax, [edx + TCP_Packet.DataOffset] |
||
335 | and eax, 11110000b |
||
336 | shr eax, 2 |
||
337 | DEBUGF 1,"TCP header size: %u\n", eax |
||
338 | sub ecx, eax |
||
339 | |||
340 | ;------------------------------- |
||
341 | ; ecx is size of tcp data |
||
342 | |||
343 | ; as a Packet has been received, update the TCB timer |
||
1159 | hidnplayr | 344 | |
1274 | hidnplayr | 345 | ; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges |
1249 | hidnplayr | 346 | test [edx + TCP_Packet.Flags], TH_ACK |
1274 | hidnplayr | 347 | jz .no_ack ; No ACK, so no data yet |
1159 | hidnplayr | 348 | |
1318 | hidnplayr | 349 | ; Calculate ACK number, in intel byte order |
1274 | hidnplayr | 350 | mov edi, [edx + TCP_Packet.AckNumber] |
351 | bswap edi |
||
352 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], edi |
||
1318 | hidnplayr | 353 | DEBUGF 1,"Setting last_ack_number to %u\n", edi |
1159 | hidnplayr | 354 | |
1274 | hidnplayr | 355 | ; Dequeue all acknowledged packets |
356 | cmp [TCP_OUT_QUEUE], 0 ; first, check if any packets are queued at all |
||
357 | je .no_ack |
||
1254 | hidnplayr | 358 | |
1318 | hidnplayr | 359 | push ebx |
360 | mov ebx, TCP_OUT_QUEUE+4 |
||
361 | call wait_mutex |
||
362 | pop ebx |
||
363 | |||
1254 | hidnplayr | 364 | push ecx |
1318 | hidnplayr | 365 | DEBUGF 1,"Removing all queued packets with smaller ACK\n" |
1249 | hidnplayr | 366 | mov ecx, TCP_QUEUE_SIZE |
1318 | hidnplayr | 367 | mov esi, TCP_OUT_QUEUE+8 |
1249 | hidnplayr | 368 | .loop: |
369 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
1254 | hidnplayr | 370 | je .maybe_next |
1274 | hidnplayr | 371 | |
372 | cmp [esi + tcp_out_queue_entry.socket], ebx |
||
373 | jne .maybe_next |
||
374 | |||
375 | cmp [esi + tcp_out_queue_entry.seq_num], edi |
||
1249 | hidnplayr | 376 | jg .maybe_next |
1159 | hidnplayr | 377 | |
1318 | hidnplayr | 378 | DEBUGF 1,"Removing a queued packet\n" |
1254 | hidnplayr | 379 | |
1249 | hidnplayr | 380 | push [esi + tcp_out_queue_entry.data_ptr] |
381 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
382 | dec [TCP_OUT_QUEUE] |
||
383 | call kernel_free |
||
1159 | hidnplayr | 384 | |
1249 | hidnplayr | 385 | .maybe_next: |
386 | add esi, tcp_out_queue_entry.size |
||
387 | loop .loop |
||
1318 | hidnplayr | 388 | |
389 | mov [TCP_OUT_QUEUE+4], 0 |
||
1274 | hidnplayr | 390 | pop ecx |
1254 | hidnplayr | 391 | |
1274 | hidnplayr | 392 | ; Now call the correct handler, depending on the socket state |
393 | .no_ack: |
||
1254 | hidnplayr | 394 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state] |
395 | |||
1249 | hidnplayr | 396 | cmp eax, TCB_LISTEN |
1254 | hidnplayr | 397 | jb .dump |
1249 | hidnplayr | 398 | cmp eax, TCB_CLOSED |
1254 | hidnplayr | 399 | ja .dump |
1159 | hidnplayr | 400 | |
1318 | hidnplayr | 401 | call dword [TCPstateHandler+eax*4-4] |
1159 | hidnplayr | 402 | |
1249 | hidnplayr | 403 | .dump: |
404 | DEBUGF 1,"Dumping TCP packet\n" |
||
1196 | hidnplayr | 405 | call kernel_free |
406 | add esp, 4 ; pop (balance stack) |
||
1159 | hidnplayr | 407 | |
1249 | hidnplayr | 408 | ret |
1196 | hidnplayr | 409 | |
410 | |||
411 | |||
412 | ;----------------------------------------------------------------- |
||
413 | ; |
||
1274 | hidnplayr | 414 | ; TCP_send (Assumes socket mutex set) |
1196 | hidnplayr | 415 | ; |
1249 | hidnplayr | 416 | ; IN: eax = socket pointer |
1274 | hidnplayr | 417 | ; bl = flags |
1281 | hidnplayr | 418 | ; ecx = number of bytes to send, may be set to 0 (single ACK) |
1274 | hidnplayr | 419 | ; esi = pointer to data |
1249 | hidnplayr | 420 | ; |
1196 | hidnplayr | 421 | ;----------------------------------------------------------------- |
1249 | hidnplayr | 422 | align 4 |
1274 | hidnplayr | 423 | TCP_send: |
1196 | hidnplayr | 424 | |
1274 | hidnplayr | 425 | DEBUGF 1,"Creating TCP packet, socket: %x, flags: %x\n",eax, bl |
1159 | hidnplayr | 426 | |
1249 | hidnplayr | 427 | mov di , IP_PROTO_TCP |
1274 | hidnplayr | 428 | add ecx, TCP_Packet.Data |
1159 | hidnplayr | 429 | |
1281 | hidnplayr | 430 | push ecx bx eax esi |
1249 | hidnplayr | 431 | ; Create an IPv4 Packet of the correct size |
432 | mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
||
433 | mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
1159 | hidnplayr | 434 | |
1249 | hidnplayr | 435 | call IPv4_create_packet |
436 | cmp edi, -1 |
||
437 | je .fail |
||
1159 | hidnplayr | 438 | |
1274 | hidnplayr | 439 | ; If there is any data, copy it first |
1249 | hidnplayr | 440 | pop esi |
1274 | hidnplayr | 441 | push edi |
442 | add edi, TCP_Packet.Data |
||
443 | sub ecx, TCP_Packet.Data |
||
1159 | hidnplayr | 444 | |
1249 | hidnplayr | 445 | shr ecx, 1 |
446 | jnc .nb |
||
447 | movsb |
||
448 | .nb: shr ecx, 1 |
||
449 | jnc .nw |
||
450 | movsw |
||
1274 | hidnplayr | 451 | .nw: test ecx, ecx |
452 | jz .nd |
||
453 | rep movsd |
||
454 | .nd: |
||
455 | pop edi |
||
1159 | hidnplayr | 456 | |
1249 | hidnplayr | 457 | ; Fill in the TCP header |
458 | pop esi |
||
1159 | hidnplayr | 459 | |
1274 | hidnplayr | 460 | ; fill in tcp sequence number |
1249 | hidnplayr | 461 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
462 | pop [edi + TCP_Packet.SequenceNumber] |
||
1159 | hidnplayr | 463 | |
1274 | hidnplayr | 464 | ; Fill in local and remote ports |
465 | push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] |
||
1249 | hidnplayr | 466 | pop dword [edi + TCP_Packet.SourcePort] |
1159 | hidnplayr | 467 | |
1274 | hidnplayr | 468 | ; Acknumber |
1254 | hidnplayr | 469 | push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
1249 | hidnplayr | 470 | pop [edi + TCP_Packet.AckNumber] |
1159 | hidnplayr | 471 | |
1274 | hidnplayr | 472 | ; Fill in other tcp options |
1249 | hidnplayr | 473 | pop cx |
474 | mov [edi + TCP_Packet.Flags], cl |
||
475 | mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes |
||
476 | mov [edi + TCP_Packet.UrgentPointer], 0 |
||
477 | mov [edi + TCP_Packet.DataOffset], 0x50 |
||
1254 | hidnplayr | 478 | mov [edi + TCP_Packet.Checksum], 0 |
1159 | hidnplayr | 479 | |
1281 | hidnplayr | 480 | ; Get size of total packet back in ecx |
481 | pop ecx |
||
1274 | hidnplayr | 482 | ; Push pointer to and size of total packet (needed for send procedure) |
1254 | hidnplayr | 483 | push edx eax |
1274 | hidnplayr | 484 | ; push socket number (for TCP_add_to_queue) |
485 | push esi |
||
1159 | hidnplayr | 486 | |
1281 | hidnplayr | 487 | ; Now, calculate the checksum |
488 | xchg cl, ch |
||
489 | pushw cx |
||
490 | xchg cl, ch |
||
1254 | hidnplayr | 491 | pushw IP_PROTO_TCP shl 8 |
1318 | hidnplayr | 492 | pushd [edi-4] ; destination address ; TODO: fix this, IPv4 packet could have options.. |
1254 | hidnplayr | 493 | pushd [edi-8] ; source address |
494 | |||
1249 | hidnplayr | 495 | xor edx, edx |
1254 | hidnplayr | 496 | mov esi, edi |
497 | call checksum_1 |
||
1249 | hidnplayr | 498 | mov ecx, 12 |
499 | mov esi, esp |
||
500 | call checksum_1 |
||
1254 | hidnplayr | 501 | ; and store it in TCP header |
1249 | hidnplayr | 502 | call checksum_2 |
503 | mov [edi + TCP_Packet.Checksum], dx |
||
1281 | hidnplayr | 504 | add esp, 10 ; remove the pseudoheader from stack |
1159 | hidnplayr | 505 | |
1249 | hidnplayr | 506 | DEBUGF 1,"Sending TCP Packet to device %x\n", ebx |
1274 | hidnplayr | 507 | mov edx, [edi + TCP_Packet.SequenceNumber] |
508 | bswap edx |
||
1254 | hidnplayr | 509 | mov esi, [ebx + ETH_DEVICE.transmit] |
1281 | hidnplayr | 510 | |
511 | pop cx ; get the length from packet, back from pseudoheader |
||
1274 | hidnplayr | 512 | pop edi |
1159 | hidnplayr | 513 | |
1281 | hidnplayr | 514 | cmp cx, TCP_Packet.Data shl 8 ; if the packet has no data |
515 | je .only_one ; send it only once |
||
516 | |||
517 | and ecx, 0x0000ffff |
||
518 | xchg cl, ch |
||
519 | sub cx, TCP_Packet.Data |
||
520 | |||
1318 | hidnplayr | 521 | add_INET (edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT) ; todo: this should only happen when packet was queued successful |
1281 | hidnplayr | 522 | mov ecx, TCP_RETRIES |
523 | |||
524 | jmp .go_for_it |
||
525 | |||
526 | .only_one: |
||
527 | mov ecx, 1 |
||
528 | .go_for_it: |
||
529 | |||
530 | mov [edi + SOCKET_head.lock], 0 |
||
531 | jmp TCP_queue ; At last send the packet! |
||
532 | |||
1249 | hidnplayr | 533 | .fail: |
1254 | hidnplayr | 534 | add esp, 2+4 |
1274 | hidnplayr | 535 | or eax, -1 |
1249 | hidnplayr | 536 | ret |
1159 | hidnplayr | 537 | |
538 | |||
1274 | hidnplayr | 539 | ;----------------------------------------------------------------- |
540 | ; |
||
541 | ; Queue a TCP packet for sending |
||
542 | ; |
||
543 | ; IN: [esp] pointer to buffer |
||
544 | ; [esp + 4] size of buffer |
||
545 | ; ebx = driver struct |
||
1318 | hidnplayr | 546 | ; edx = sequence number of this packet in intel byte order |
1274 | hidnplayr | 547 | ; esi = sender proc |
548 | ; edi = socket number |
||
1318 | hidnplayr | 549 | |
1274 | hidnplayr | 550 | ; OUT: / |
551 | ; |
||
552 | ;----------------------------------------------------------------- |
||
553 | align 4 |
||
554 | TCP_queue: |
||
1159 | hidnplayr | 555 | |
1274 | hidnplayr | 556 | DEBUGF 1,"Adding packet to TCP queue, buffer: %x, size: %u, driver: %x, acknum: %u\n", [esp], [esp+4], ebx, edx |
1159 | hidnplayr | 557 | |
1274 | hidnplayr | 558 | cmp [TCP_OUT_QUEUE], TCP_QUEUE_SIZE |
559 | jge .full |
||
1159 | hidnplayr | 560 | |
1318 | hidnplayr | 561 | push ebx |
562 | mov ebx, TCP_OUT_QUEUE+4 |
||
563 | call wait_mutex |
||
564 | pop ebx |
||
565 | |||
1274 | hidnplayr | 566 | mov ecx, TCP_QUEUE_SIZE |
1318 | hidnplayr | 567 | mov eax, TCP_OUT_QUEUE+8 |
1274 | hidnplayr | 568 | .loop: |
569 | cmp [eax + tcp_out_queue_entry.data_ptr], 0 |
||
570 | je .found_it |
||
571 | add eax, tcp_out_queue_entry.size |
||
572 | loop .loop |
||
573 | |||
1318 | hidnplayr | 574 | add esp, 4 |
1274 | hidnplayr | 575 | .full: ; silently discard the packet |
576 | DEBUGF 1,"TCP queue is full!\n" |
||
577 | call kernel_free |
||
578 | add esp, 4 |
||
579 | |||
580 | ret |
||
581 | |||
582 | .found_it: ; eax points to empty queue entry |
||
583 | |||
1318 | hidnplayr | 584 | mov [eax + tcp_out_queue_entry.retries], TCP_RETRIES |
1274 | hidnplayr | 585 | pop [eax + tcp_out_queue_entry.data_ptr] |
586 | pop [eax + tcp_out_queue_entry.data_size] |
||
587 | mov [eax + tcp_out_queue_entry.ttl], 1 ; send immediately |
||
588 | mov [eax + tcp_out_queue_entry.owner], ebx |
||
589 | mov [eax + tcp_out_queue_entry.sendproc], esi |
||
590 | mov [eax + tcp_out_queue_entry.seq_num], edx |
||
591 | mov [eax + tcp_out_queue_entry.socket], edi |
||
592 | |||
593 | inc [TCP_OUT_QUEUE] |
||
594 | |||
1318 | hidnplayr | 595 | sub eax, TCP_OUT_QUEUE+8 |
596 | shr eax, 5 |
||
597 | DEBUGF 1,"Added to queue in pos %u, total queued packets: %u\n", eax, [TCP_OUT_QUEUE+8] |
||
1274 | hidnplayr | 598 | |
1318 | hidnplayr | 599 | mov [TCP_OUT_QUEUE+4], 0 |
600 | |||
1274 | hidnplayr | 601 | ret |
602 | |||
603 | |||
1318 | hidnplayr | 604 | ;----------------------------------------------------------------- |
605 | ; |
||
606 | ; IN: ebx = socket |
||
607 | ; ecx = ack number |
||
608 | ; |
||
609 | ; OUT: / |
||
610 | ; |
||
611 | ;----------------------------------------------------------------- |
||
612 | align 4 |
||
613 | TCP_queue_ack: |
||
1274 | hidnplayr | 614 | |
1318 | hidnplayr | 615 | DEBUGF 1,"Adding ACK to TCP queue, socket: %x, acknum: %u\n", ebx, ecx |
1274 | hidnplayr | 616 | |
1318 | hidnplayr | 617 | cmp [TCP_OUT_QUEUE], TCP_QUEUE_SIZE |
618 | jge .full |
||
1274 | hidnplayr | 619 | |
1318 | hidnplayr | 620 | push ebx ecx |
621 | mov ebx, TCP_OUT_QUEUE+4 |
||
622 | call wait_mutex |
||
623 | |||
624 | mov ecx, TCP_QUEUE_SIZE |
||
625 | mov eax, TCP_OUT_QUEUE+8 |
||
626 | .loop: |
||
627 | cmp [eax + tcp_out_queue_entry.data_ptr], 0 |
||
628 | je .found_it |
||
629 | add eax, tcp_out_queue_entry.size |
||
630 | loop .loop |
||
631 | |||
632 | add esp, 8 |
||
633 | .full: ; silently discard the packet |
||
634 | DEBUGF 1,"TCP queue is full!\n" |
||
635 | ret |
||
636 | |||
637 | .found_it: ; eax points to empty queue entry |
||
638 | |||
639 | pop [eax + tcp_out_queue_entry.data_size] ; ACK number |
||
640 | mov [eax + tcp_out_queue_entry.data_ptr], -1 ; ACK packet |
||
641 | pop [eax + tcp_out_queue_entry.socket] |
||
642 | mov [eax + tcp_out_queue_entry.retries], 1 |
||
643 | mov [eax + tcp_out_queue_entry.ttl], 20 ; 200 ms |
||
644 | |||
645 | inc [TCP_OUT_QUEUE] |
||
646 | |||
647 | sub eax, TCP_OUT_QUEUE+8 |
||
648 | shr eax, 5 |
||
649 | DEBUGF 1,"Added to queue in pos %u, total queued packets: %u\n", eax, [TCP_OUT_QUEUE+8] |
||
650 | |||
651 | mov [TCP_OUT_QUEUE+4], 0 |
||
652 | |||
653 | ret |
||
654 | |||
655 | |||
656 | ; IN: eax = socket pointer |
||
657 | ; ebx = device structure |
||
658 | ; ecx = ack number |
||
659 | |||
660 | align 4 |
||
661 | TCP_send_ack: |
||
662 | |||
663 | DEBUGF 1,"Creating TCP ACK packet, socket: %x, acknum: %x\n", eax, ecx |
||
664 | |||
665 | push ecx eax |
||
666 | |||
667 | mov di , IP_PROTO_TCP |
||
668 | mov ecx, TCP_Packet.Data |
||
669 | ; Create an IPv4 Packet of the correct size |
||
670 | mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP] |
||
671 | mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
672 | |||
673 | call IPv4_create_packet |
||
674 | cmp edi, -1 |
||
675 | je .fail |
||
676 | |||
677 | pop ecx |
||
678 | |||
679 | ; fill in tcp sequence number |
||
680 | push [ecx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] |
||
681 | pop [edi + TCP_Packet.SequenceNumber] |
||
682 | |||
683 | ; Fill in local and remote ports |
||
684 | push dword [ecx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] |
||
685 | pop dword [edi + TCP_Packet.SourcePort] |
||
686 | |||
687 | ; Acknumber |
||
688 | pop [edi + TCP_Packet.AckNumber] |
||
689 | |||
690 | ; Fill in other tcp options |
||
691 | mov [edi + TCP_Packet.Flags], TH_ACK |
||
692 | mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes |
||
693 | mov [edi + TCP_Packet.UrgentPointer], 0 |
||
694 | mov [edi + TCP_Packet.DataOffset], 0x50 |
||
695 | mov [edi + TCP_Packet.Checksum], 0 |
||
696 | |||
697 | ; Push pointer to and size of total packet (needed for send procedure) |
||
698 | push edx eax esi |
||
699 | |||
700 | ; Now, calculate the checksum |
||
701 | pushw TCP_Packet.Data shl 8 |
||
702 | pushw IP_PROTO_TCP shl 8 |
||
703 | pushd [edi-4] ; destination address ; TODO: fix this, IPv4 packet could have options.. |
||
704 | pushd [edi-8] ; source address |
||
705 | |||
706 | xor edx, edx |
||
707 | mov ecx, 12 |
||
708 | mov esi, esp |
||
709 | call checksum_1 |
||
710 | call checksum_2 |
||
711 | mov [edi + TCP_Packet.Checksum], dx |
||
712 | add esp, 12 ; remove the pseudoheader from stack |
||
713 | |||
714 | pop eax |
||
715 | call eax |
||
716 | call kernel_free |
||
717 | add esp, 4 ; pop (balance stack) |
||
718 | ret |
||
719 | |||
720 | .fail: |
||
721 | add esp, 8 |
||
722 | ret |
||
723 | |||
724 | |||
725 | |||
726 | |||
727 | ;----------------------------------------------------------------- |
||
728 | ; |
||
729 | ; Remove all queued TCP packets for a specified socket |
||
730 | ; |
||
731 | ; IN: eax = socket number |
||
732 | ; OUT: / |
||
733 | ; |
||
734 | ; destoys esi and ecx |
||
735 | ; |
||
736 | ;----------------------------------------------------------------- |
||
737 | |||
738 | align 4 |
||
739 | TCP_remove_socket: |
||
740 | |||
741 | cmp [TCP_OUT_QUEUE], 0 |
||
742 | je .skip |
||
743 | |||
744 | mov ebx, TCP_OUT_QUEUE+4 |
||
745 | call wait_mutex |
||
746 | |||
747 | mov eax, TCP_QUEUE_SIZE |
||
748 | mov ecx, [TCP_OUT_QUEUE] |
||
749 | mov esi, TCP_OUT_QUEUE+8 |
||
750 | |||
751 | .loop: |
||
752 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
753 | jz .maybenext |
||
754 | cmp [esi + tcp_out_queue_entry.socket], eax |
||
755 | jnz .maybenext |
||
756 | |||
757 | push [esi + tcp_out_queue_entry.data_ptr] |
||
758 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
759 | dec [TCP_OUT_QUEUE] |
||
760 | call kernel_free |
||
761 | |||
762 | .maybenext: |
||
763 | add esi, tcp_out_queue_entry.size |
||
764 | loop .loop |
||
765 | |||
766 | mov [TCP_OUT_QUEUE+4], 0 |
||
767 | .skip: |
||
768 | ret |
||
769 | |||
770 | |||
771 | |||
772 | |||
773 | |||
1255 | hidnplayr | 774 | ;---------- TCB state handlers start here |
775 | |||
776 | |||
777 | |||
778 | |||
1249 | hidnplayr | 779 | align 4 |
780 | stateTCB_LISTEN: |
||
1254 | hidnplayr | 781 | |
782 | DEBUGF 1,"TCBStateHandler: Listen\n" |
||
783 | |||
1274 | hidnplayr | 784 | test [edx + TCP_Packet.Flags], TH_SYN ; SYN packet? => send syn+ack, open new socket and set connection to established |
1159 | hidnplayr | 785 | jz .exit |
1274 | hidnplayr | 786 | ; Exit if backlog queue is full |
1256 | clevermous | 787 | mov ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur] |
788 | cmp ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog] |
||
789 | jae .exit |
||
1274 | hidnplayr | 790 | ; Allocate new socket |
791 | push esi edi |
||
1256 | clevermous | 792 | call net_socket_alloc |
793 | test eax, eax |
||
1274 | hidnplayr | 794 | jz .fail |
795 | ; Copy structure from current socket to new, including lock |
||
796 | lea esi, [ebx + SOCKET_head.PID] ; yes, PID must also be copied |
||
1256 | clevermous | 797 | lea edi, [eax + SOCKET_head.PID] |
798 | mov ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4 |
||
799 | rep movsd |
||
800 | pop edi esi |
||
1274 | hidnplayr | 801 | ; Push pointer to new socket to queue |
1256 | clevermous | 802 | movzx ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur] |
803 | inc [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur] |
||
804 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax |
||
1159 | hidnplayr | 805 | |
1256 | clevermous | 806 | mov [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address |
807 | mov cx, [edx + TCP_Packet.SourcePort] |
||
808 | mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx |
||
809 | mov ecx, [edx + TCP_Packet.SequenceNumber] |
||
810 | mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx |
||
811 | mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx |
||
812 | lea esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
||
1249 | hidnplayr | 813 | inc_INET esi ; RCV.NXT |
1256 | clevermous | 814 | mov ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS] |
815 | mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx |
||
1159 | hidnplayr | 816 | |
1254 | hidnplayr | 817 | mov [ebx + SOCKET_head.lock], 0 |
818 | |||
1256 | clevermous | 819 | push eax |
1274 | hidnplayr | 820 | ; Now construct the response |
1159 | hidnplayr | 821 | mov bl, TH_SYN + TH_ACK |
1274 | hidnplayr | 822 | xor ecx, ecx |
823 | call TCP_send |
||
1256 | clevermous | 824 | pop eax |
1159 | hidnplayr | 825 | |
1274 | hidnplayr | 826 | mov [eax + SOCKET_head.lock], 0 |
1256 | clevermous | 827 | mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED |
828 | call notify_network_event |
||
829 | ret |
||
1159 | hidnplayr | 830 | |
831 | .exit: |
||
1254 | hidnplayr | 832 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 833 | ret |
834 | |||
1274 | hidnplayr | 835 | .fail: |
836 | add esp, 8 |
||
837 | mov [ebx + SOCKET_head.lock], 0 |
||
838 | ret |
||
1159 | hidnplayr | 839 | |
1274 | hidnplayr | 840 | |
1249 | hidnplayr | 841 | align 4 |
842 | stateTCB_SYN_SENT: |
||
1254 | hidnplayr | 843 | |
844 | DEBUGF 1,"TCBStateHandler: Syn_Sent\n" |
||
845 | |||
1159 | hidnplayr | 846 | ; We are awaiting an ACK to our SYN, with a SYM |
847 | ; Look at control flags - expecting an ACK |
||
848 | |||
1249 | hidnplayr | 849 | mov al, [edx + TCP_Packet.Flags] |
1274 | hidnplayr | 850 | |
851 | test al, TH_RST |
||
852 | jnz .reset ; jump if RST bit set |
||
853 | |||
854 | push [edx + TCP_Packet.SequenceNumber] ;; |
||
855 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] ;; |
||
856 | inc_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT) ;; |
||
857 | |||
858 | |||
859 | push [edx + TCP_Packet.AckNumber] ;;;;;; |
||
860 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT] ;;;;;; |
||
861 | |||
1159 | hidnplayr | 862 | and al, TH_SYN + TH_ACK |
1274 | hidnplayr | 863 | jz .exit ; jump if none of the following is set: RST, SYN, ACK |
1159 | hidnplayr | 864 | |
1274 | hidnplayr | 865 | test al, TH_ACK |
866 | jz .onlysyn ; jump if only SYN bit is set |
||
1159 | hidnplayr | 867 | |
1274 | hidnplayr | 868 | ; If we arrived here, SYN and ACK are set |
1159 | hidnplayr | 869 | |
1254 | hidnplayr | 870 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED |
1274 | hidnplayr | 871 | pushw TH_ACK |
1159 | hidnplayr | 872 | |
1274 | hidnplayr | 873 | .send: ; Send an ACK |
1254 | hidnplayr | 874 | mov eax, ebx |
1274 | hidnplayr | 875 | pop bx |
876 | push eax |
||
877 | xor ecx, ecx |
||
878 | call TCP_send |
||
1159 | hidnplayr | 879 | pop ebx |
880 | |||
881 | .exit: |
||
1254 | hidnplayr | 882 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 883 | ret |
884 | |||
1274 | hidnplayr | 885 | .reset: |
886 | ; TODO: .... |
||
1159 | hidnplayr | 887 | |
1274 | hidnplayr | 888 | ; remove all queued TCP packets for this connection ! |
1249 | hidnplayr | 889 | |
1274 | hidnplayr | 890 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED |
891 | mov [ebx + SOCKET_head.lock], 0 |
||
892 | ret |
||
893 | |||
894 | .onlysyn: |
||
895 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED |
||
896 | pushw TH_SYN + TH_ACK |
||
897 | jmp .send |
||
898 | |||
899 | |||
900 | |||
1249 | hidnplayr | 901 | align 4 |
902 | stateTCB_SYN_RECEIVED: |
||
1254 | hidnplayr | 903 | |
904 | DEBUGF 1,"TCBStateHandler: Syn_received\n" |
||
905 | |||
1274 | hidnplayr | 906 | test [edx + TCP_Packet.Flags], TH_RST ; reset connection? => LISTEN |
1159 | hidnplayr | 907 | jz .check_ack |
908 | |||
1274 | hidnplayr | 909 | push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort] |
910 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort] |
||
911 | push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP] |
||
912 | pop [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP] |
||
1159 | hidnplayr | 913 | |
1254 | hidnplayr | 914 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN |
1159 | hidnplayr | 915 | jmp .exit |
916 | |||
917 | .check_ack: |
||
1274 | hidnplayr | 918 | test [edx + TCP_Packet.Flags], TH_ACK ; ACK? => connection established! |
1159 | hidnplayr | 919 | jz .exit |
920 | |||
1254 | hidnplayr | 921 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED |
1256 | clevermous | 922 | mov eax, ebx |
923 | call notify_network_event |
||
1159 | hidnplayr | 924 | |
925 | .exit: |
||
1254 | hidnplayr | 926 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 927 | ret |
928 | |||
929 | |||
1318 | hidnplayr | 930 | if 0 |
1249 | hidnplayr | 931 | |
1318 | hidnplayr | 932 | |
1249 | hidnplayr | 933 | align 4 |
934 | stateTCB_ESTABLISHED: |
||
1254 | hidnplayr | 935 | |
936 | DEBUGF 1,"TCBStateHandler: Established\n" |
||
937 | |||
1255 | hidnplayr | 938 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
1274 | hidnplayr | 939 | bswap eax |
940 | DEBUGF 1,"RCV_NXT is set to:%u\n", eax |
||
941 | bswap eax |
||
1255 | hidnplayr | 942 | cmp eax, [edx + TCP_Packet.SequenceNumber] |
1318 | hidnplayr | 943 | jne .exit ;;;;;; |
944 | |||
945 | ; check if we received an ACK |
||
946 | test [edx + TCP_Packet.Flags], TH_ACK |
||
947 | jz .no_ack |
||
948 | |||
949 | mov ax, [edx + TCP_Packet.Window] |
||
950 | xchg al, ah |
||
951 | cmp ax, 1024 |
||
952 | ja @f |
||
953 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1 |
||
954 | @@: |
||
955 | .no_ack: |
||
956 | |||
957 | ; Now, see if we received any data |
||
958 | test ecx, ecx |
||
959 | jz .nodata |
||
960 | |||
961 | ; Calculate next sequencenumber |
||
962 | add_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT) |
||
963 | |||
964 | push edx |
||
965 | DEBUGF 1,"Got %u bytes data!\n", ecx |
||
966 | ; calculate header length |
||
967 | movzx eax, [edx + TCP_Packet.DataOffset] |
||
968 | and eax, 11110000b |
||
969 | shr eax, 2 |
||
970 | DEBUGF 1,"TCP header size: %u\n", eax |
||
971 | add edx, eax ; now edx points to data |
||
972 | |||
973 | add esp, 4 |
||
974 | pop esi ; pointer to buffer |
||
975 | add esp, 4 |
||
976 | |||
977 | sub edx, esi |
||
978 | mov edi, edx ; offset |
||
979 | mov eax, ebx ; socket ptr |
||
980 | |||
981 | call socket_internal_receiver ; Place the data from packet into socket |
||
982 | |||
983 | ; lea ebx, [eax + SOCKET_head.lock] |
||
984 | ; call wait_mutex |
||
985 | mov ebx, eax |
||
986 | pop edx |
||
987 | |||
988 | test [edx + TCP_Packet.Flags], TH_FIN + TH_RST |
||
989 | jz .ack |
||
990 | |||
991 | .nodata: |
||
992 | test [edx + TCP_Packet.Flags], TH_FIN + TH_RST |
||
993 | jz .exit |
||
994 | |||
995 | ; Send an ACK to that fin, and enter closewait state |
||
996 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT |
||
997 | ; Remove all resend entries from the queue |
||
998 | mov eax, ebx |
||
999 | call TCP_remove_socket |
||
1000 | |||
1001 | .ack: |
||
1002 | push ebx |
||
1003 | mov ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
||
1004 | call TCP_queue_ack |
||
1005 | pop ebx |
||
1006 | |||
1007 | .exit: |
||
1008 | mov [ebx + SOCKET_head.lock], 0 |
||
1009 | ret |
||
1010 | |||
1011 | |||
1012 | end if |
||
1013 | |||
1014 | |||
1015 | align 4 |
||
1016 | stateTCB_ESTABLISHED: |
||
1017 | |||
1018 | DEBUGF 1,"TCBStateHandler: Established\n" |
||
1019 | |||
1020 | mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT] |
||
1021 | bswap eax |
||
1022 | DEBUGF 1,"RCV_NXT is set to:%u\n", eax |
||
1023 | bswap eax |
||
1024 | cmp eax, [edx + TCP_Packet.SequenceNumber] |
||
1255 | hidnplayr | 1025 | jne .exit |
1026 | |||
1274 | hidnplayr | 1027 | ; Calculate next sequencenumber |
1028 | add_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT) |
||
1159 | hidnplayr | 1029 | |
1318 | hidnplayr | 1030 | test [edx + TCP_Packet.Flags], TH_FIN + TH_RST |
1274 | hidnplayr | 1031 | jnz .fin |
1159 | hidnplayr | 1032 | |
1033 | .check_ack: |
||
1249 | hidnplayr | 1034 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 1035 | jz .exit |
1036 | |||
1254 | hidnplayr | 1037 | DEBUGF 1,"Received ACK\n" |
1274 | hidnplayr | 1038 | ; First, look at the incoming window. If this is less than or equal to 1024, |
1039 | ; Set the socket window timer to 1. This will stop an additional Packets being queued. |
||
1040 | ; ** I may need to tweak this value, since I do not know how many Packets are already queued |
||
1255 | hidnplayr | 1041 | push ecx |
1249 | hidnplayr | 1042 | mov cx, [edx + TCP_Packet.Window] |
1159 | hidnplayr | 1043 | xchg cl, ch |
1044 | cmp cx, 1024 |
||
1045 | ja @f |
||
1249 | hidnplayr | 1046 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1 |
1255 | hidnplayr | 1047 | @@: |
1048 | pop ecx |
||
1159 | hidnplayr | 1049 | |
1274 | hidnplayr | 1050 | ; Now, see if we received any data |
1255 | hidnplayr | 1051 | test ecx, ecx |
1281 | hidnplayr | 1052 | jz .exit |
1159 | hidnplayr | 1053 | |
1274 | hidnplayr | 1054 | DEBUGF 1,"Got %u bytes data!\n", ecx |
1055 | ; calculate header length |
||
1056 | movzx eax, [edx + TCP_Packet.DataOffset] |
||
1057 | and eax, 11110000b |
||
1058 | shr eax, 2 |
||
1059 | DEBUGF 1,"TCP header size: %u\n", eax |
||
1281 | hidnplayr | 1060 | add edx, eax ; now edx points to data |
1061 | |||
1274 | hidnplayr | 1062 | add esp, 4 |
1281 | hidnplayr | 1063 | pop esi ; pointer to buffer |
1274 | hidnplayr | 1064 | add esp, 4 |
1281 | hidnplayr | 1065 | |
1249 | hidnplayr | 1066 | sub edx, esi |
1281 | hidnplayr | 1067 | mov edi, edx ; offset |
1068 | mov eax, ebx ; socket ptr |
||
1159 | hidnplayr | 1069 | |
1281 | hidnplayr | 1070 | call socket_internal_receiver ; Place the data from packet into socket |
1071 | |||
1318 | hidnplayr | 1072 | lea ebx, [eax + SOCKET_head.lock] |
1073 | call wait_mutex |
||
1074 | mov ebx, eax |
||
1281 | hidnplayr | 1075 | |
1159 | hidnplayr | 1076 | .ack: |
1254 | hidnplayr | 1077 | mov eax, ebx |
1159 | hidnplayr | 1078 | mov bl, TH_ACK |
1274 | hidnplayr | 1079 | push eax |
1080 | xor ecx, ecx |
||
1081 | call TCP_send ; send the ack |
||
1082 | pop ebx |
||
1159 | hidnplayr | 1083 | .exit: |
1254 | hidnplayr | 1084 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 1085 | ret |
1086 | |||
1318 | hidnplayr | 1087 | .fin: ; we received a FIN or RESET |
1274 | hidnplayr | 1088 | ; Remove all resend entries from the queue |
1089 | mov ecx, TCP_QUEUE_SIZE |
||
1090 | mov esi, TCP_OUT_QUEUE+4 |
||
1159 | hidnplayr | 1091 | |
1274 | hidnplayr | 1092 | .removeloop: |
1093 | cmp [esi + tcp_out_queue_entry.data_ptr], 0 |
||
1094 | je .maybe_next |
||
1249 | hidnplayr | 1095 | |
1274 | hidnplayr | 1096 | ; TODO: check if the packets belong to the same tcp connection ! |
1097 | |||
1098 | DEBUGF 1,"Removing a queued packet\n" |
||
1099 | |||
1100 | push [esi + tcp_out_queue_entry.data_ptr] |
||
1101 | mov [esi + tcp_out_queue_entry.data_ptr], 0 |
||
1102 | dec [TCP_OUT_QUEUE] |
||
1103 | call kernel_free |
||
1104 | |||
1105 | .maybe_next: |
||
1106 | add esi, tcp_out_queue_entry.size |
||
1107 | loop .removeloop |
||
1108 | |||
1109 | ; Send an ACK to that fin, and enter closewait state |
||
1318 | hidnplayr | 1110 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING |
1274 | hidnplayr | 1111 | jmp .check_ack |
1112 | |||
1113 | |||
1249 | hidnplayr | 1114 | align 4 |
1115 | stateTCB_FIN_WAIT_1: |
||
1254 | hidnplayr | 1116 | |
1117 | DEBUGF 1,"TCBStateHandler: Fin_wait_1\n" |
||
1118 | |||
1159 | hidnplayr | 1119 | ; We can either receive an ACK of a fin, or a fin |
1249 | hidnplayr | 1120 | mov al, [edx + TCP_Packet.Flags] |
1159 | hidnplayr | 1121 | and al, TH_FIN + TH_ACK |
1122 | |||
1123 | cmp al, TH_ACK |
||
1124 | jne @f |
||
1125 | |||
1126 | ; It was an ACK |
||
1254 | hidnplayr | 1127 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2 |
1159 | hidnplayr | 1128 | jmp .exit |
1129 | |||
1254 | hidnplayr | 1130 | @@: mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING |
1159 | hidnplayr | 1131 | cmp al, TH_FIN |
1132 | je @f |
||
1254 | hidnplayr | 1133 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT |
1159 | hidnplayr | 1134 | |
1274 | hidnplayr | 1135 | @@: |
1159 | hidnplayr | 1136 | ; Send an ACK |
1254 | hidnplayr | 1137 | mov eax, ebx |
1159 | hidnplayr | 1138 | mov bl, TH_ACK |
1274 | hidnplayr | 1139 | push eax |
1140 | xor ecx, ecx |
||
1141 | call TCP_send |
||
1142 | pop ebx |
||
1159 | hidnplayr | 1143 | |
1144 | .exit: |
||
1254 | hidnplayr | 1145 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 1146 | ret |
1147 | |||
1148 | |||
1249 | hidnplayr | 1149 | |
1150 | align 4 |
||
1151 | stateTCB_FIN_WAIT_2: |
||
1254 | hidnplayr | 1152 | |
1153 | DEBUGF 1,"TCBStateHandler: Fin_wait_2\n" |
||
1154 | |||
1249 | hidnplayr | 1155 | test [edx + TCP_Packet.Flags], TH_FIN |
1159 | hidnplayr | 1156 | jz .exit |
1157 | |||
1158 | ; Change state, as we have a fin |
||
1254 | hidnplayr | 1159 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT |
1159 | hidnplayr | 1160 | |
1161 | ; Send an ACK |
||
1254 | hidnplayr | 1162 | mov eax, ebx |
1159 | hidnplayr | 1163 | mov bl, TH_ACK |
1274 | hidnplayr | 1164 | push eax |
1165 | xor ecx, ecx |
||
1166 | call TCP_send |
||
1167 | pop ebx |
||
1159 | hidnplayr | 1168 | |
1169 | .exit: |
||
1254 | hidnplayr | 1170 | mov [ebx + SOCKET_head.lock], 0 |
1159 | hidnplayr | 1171 | ret |
1172 | |||
1173 | |||
1249 | hidnplayr | 1174 | |
1175 | align 4 |
||
1176 | stateTCB_CLOSE_WAIT: |
||
1254 | hidnplayr | 1177 | |
1178 | DEBUGF 1,"TCBStateHandler: close_wait\n" |
||
1159 | hidnplayr | 1179 | ; Intentionally left empty |
1180 | ; socket_close_tcp handles this |
||
1254 | hidnplayr | 1181 | |
1182 | mov [ebx + SOCKET_head.lock], 0 |
||
1159 | hidnplayr | 1183 | ret |
1184 | |||
1185 | |||
1249 | hidnplayr | 1186 | |
1187 | align 4 |
||
1188 | stateTCB_CLOSING: |
||
1254 | hidnplayr | 1189 | |
1190 | DEBUGF 1,"TCBStateHandler: closingn\n" |
||
1191 | |||
1159 | hidnplayr | 1192 | ; We can either receive an ACK of a fin, or a fin |
1249 | hidnplayr | 1193 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 1194 | jz .exit |
1195 | |||
1254 | hidnplayr | 1196 | mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT |
1159 | hidnplayr | 1197 | |
1198 | .exit: |
||
1254 | hidnplayr | 1199 | |
1200 | mov [ebx + SOCKET_head.lock], 0 |
||
1159 | hidnplayr | 1201 | ret |
1202 | |||
1203 | |||
1249 | hidnplayr | 1204 | align 4 |
1205 | stateTCB_LAST_ACK: |
||
1254 | hidnplayr | 1206 | |
1207 | DEBUGF 1,"TCBStateHandler: last_ackn\n" |
||
1208 | |||
1159 | hidnplayr | 1209 | ; Look at control flags - expecting an ACK |
1249 | hidnplayr | 1210 | test [edx + TCP_Packet.Flags], TH_ACK |
1159 | hidnplayr | 1211 | jz .exit |
1212 | |||
1254 | hidnplayr | 1213 | mov [ebx + SOCKET_head.lock], 0 |
1214 | |||
1159 | hidnplayr | 1215 | ; delete the socket |
1216 | stdcall net_socket_free, ebx |
||
1217 | |||
1218 | .exit: |
||
1219 | ret |
||
1220 | |||
1221 | |||
1249 | hidnplayr | 1222 | align 4 |
1223 | stateTCB_TIME_WAIT: |
||
1254 | hidnplayr | 1224 | |
1225 | DEBUGF 1,"TCBStateHandler: time_wait\n" |
||
1226 | |||
1227 | mov [ebx + SOCKET_head.lock], 0 |
||
1228 | |||
1159 | hidnplayr | 1229 | ret |
1230 | |||
1231 | |||
1249 | hidnplayr | 1232 | align 4 |
1233 | stateTCB_CLOSED: |
||
1254 | hidnplayr | 1234 | |
1235 | DEBUGF 1,"TCBStateHandler: closed\n" |
||
1236 | |||
1237 | mov [ebx + SOCKET_head.lock], 0 |
||
1238 | |||
1159 | hidnplayr | 1239 | ret |
1240 | |||
1241 | |||
1242 | |||
1254 | hidnplayr | 1243 | ;--------------------------------------------------------------------------- |
1244 | ; |
||
1245 | ; TCP_API |
||
1246 | ; |
||
1247 | ; This function is called by system function 75 |
||
1248 | ; |
||
1249 | ; IN: subfunction number in bl |
||
1250 | ; device number in bh |
||
1251 | ; ecx, edx, .. depends on subfunction |
||
1252 | ; |
||
1253 | ; OUT: |
||
1254 | ; |
||
1255 | ;--------------------------------------------------------------------------- |
||
1256 | align 4 |
||
1257 | TCP_API: |
||
1258 | |||
1259 | movzx eax, bh |
||
1260 | shl eax, 2 |
||
1261 | |||
1262 | test bl, bl |
||
1263 | jz .packets_tx ; 0 |
||
1264 | dec bl |
||
1265 | jz .packets_rx ; 1 |
||
1266 | |||
1267 | .error: |
||
1268 | mov eax, -1 |
||
1269 | ret |
||
1270 | |||
1271 | .packets_tx: |
||
1272 | add eax, TCP_PACKETS_TX |
||
1273 | mov eax, [eax] |
||
1274 | ret |
||
1275 | |||
1276 | .packets_rx: |
||
1277 | add eax, TCP_PACKETS_RX |
||
1278 | mov eax, [eax] |
||
1279 | ret |