Rev 914 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
431 | serge | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
2971 | Serge | 3 | ;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
431 | serge | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;; TCP.INC ;; |
||
7 | ;; ;; |
||
8 | ;; TCP Processes for Menuet OS TCP/IP stack ;; |
||
9 | ;; ;; |
||
10 | ;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
||
11 | ;; ;; |
||
12 | ;; See file COPYING for details ;; |
||
13 | ;; v0.6 : Added reset handling in the established state ;; |
||
14 | ;; Added a timer per socket to allow delays when ;; |
||
15 | ;; rx window gets below 1KB ;; |
||
914 | serge | 16 | ;; ;; |
431 | serge | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1 | ha | 18 | |
593 | mikedld | 19 | $Revision: 2971 $ |
20 | |||
21 | |||
261 | hidnplayr | 22 | ; TCP TCB states |
23 | TCB_LISTEN equ 1 |
||
24 | TCB_SYN_SENT equ 2 |
||
25 | TCB_SYN_RECEIVED equ 3 |
||
26 | TCB_ESTABLISHED equ 4 |
||
27 | TCB_FIN_WAIT_1 equ 5 |
||
28 | TCB_FIN_WAIT_2 equ 6 |
||
29 | TCB_CLOSE_WAIT equ 7 |
||
30 | TCB_CLOSING equ 8 |
||
31 | TCB_LAST_ACK equ 9 |
||
914 | serge | 32 | TCB_TIMED_WAIT equ 10 |
261 | hidnplayr | 33 | TCB_CLOSED equ 11 |
1 | ha | 34 | |
914 | serge | 35 | TH_FIN = 0x01 |
36 | TH_SYN = 0x02 |
||
37 | TH_RST = 0x04 |
||
38 | TH_PUSH = 0x08 |
||
39 | TH_ACK = 0x10 |
||
40 | TH_URG = 0x20 |
||
41 | |||
261 | hidnplayr | 42 | TWOMSL equ 10 ; # of secs to wait before closing socket |
43 | |||
44 | TCP_RETRIES equ 5 ; Number of times to resend a packet |
||
45 | TCP_TIMEOUT equ 10 ; resend if not replied to in x hs |
||
46 | |||
1 | ha | 47 | ;******************************************************************* |
48 | ; Interface |
||
49 | ; |
||
50 | ; tcp_tx_handler Handles the TCP transmit queue |
||
51 | ; tcp_rx The protocol handler for received data |
||
52 | ; buildTCPPacket fills in the packet headers and data |
||
53 | ; tcpStateMachine Main state machine for received TCP packets |
||
54 | ; tcp_tcb_handler 1s timer, to erase tcb's in TIME_WAIT state |
||
55 | ; |
||
56 | ;******************************************************************* |
||
57 | |||
58 | |||
261 | hidnplayr | 59 | ; TCP Payload ( Data field in IP datagram ) |
60 | ; |
||
61 | ; 0 1 2 3 |
||
62 | ; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
||
63 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
64 | ;20 | Source Port | Destination Port | |
||
65 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
66 | ;24 | Sequence Number | |
||
67 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
68 | ;28 | Acknowledgment Number | |
||
69 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
70 | ;32 | Data | |U|A|P|R|S|F| | |
||
71 | ; | Offset| Reserved |R|C|S|S|Y|I| Window | |
||
72 | ; | | |G|K|H|T|N|N| | |
||
73 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
74 | ;36 | Checksum | Urgent Pointer | |
||
75 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
76 | ;40 | Options | Padding | |
||
77 | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
78 | ; | data |
||
1 | ha | 79 | |
261 | hidnplayr | 80 | |
81 | struc TCP_PACKET |
||
82 | { .SourcePort dw ? ;+00 |
||
83 | .DestinationPort dw ? ;+02 |
||
84 | .SequenceNumber dd ? ;+04 |
||
85 | .AckNumber dd ? ;+08 |
||
86 | .DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7] |
||
87 | .Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN |
||
88 | .Window dw ? ;+14 |
||
89 | .Checksum dw ? ;+16 |
||
90 | .UrgentPointer dw ? ;+18 |
||
91 | .Options rb 3 ;+20 |
||
92 | .Padding db ? ;+23 |
||
93 | .Data db ? ;+24 |
||
94 | } |
||
95 | |||
96 | virtual at 0 |
||
97 | TCP_PACKET TCP_PACKET |
||
98 | end virtual |
||
99 | |||
100 | |||
101 | |||
1 | ha | 102 | ;*************************************************************************** |
103 | ; Function |
||
104 | ; tcp_tcb_handler |
||
105 | ; |
||
106 | ; Description |
||
107 | ; Handles sockets in the timewait state, closing them |
||
108 | ; when the TCB timer expires |
||
109 | ; |
||
110 | ;*************************************************************************** |
||
914 | serge | 111 | |
112 | proc tcp_tcb_handler stdcall uses ebx |
||
1 | ha | 113 | ; scan through all the sockets, decrementing active timers |
114 | |||
914 | serge | 115 | mov ebx, net_sockets |
1 | ha | 116 | |
914 | serge | 117 | cmp [ebx + SOCKET.NextPtr], 0 |
118 | je .exit |
||
2971 | Serge | 119 | ;DEBUGF 1, "K : sockets:\n" |
1 | ha | 120 | |
914 | serge | 121 | .next_socket: |
122 | mov ebx, [ebx + SOCKET.NextPtr] |
||
123 | or ebx, ebx |
||
124 | jz .exit |
||
1 | ha | 125 | |
2971 | Serge | 126 | ;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] |
1 | ha | 127 | |
914 | serge | 128 | cmp [ebx + SOCKET.TCBTimer], 0 |
129 | jne .decrement_tcb |
||
130 | cmp [ebx + SOCKET.wndsizeTimer], 0 |
||
131 | jne .decrement_wnd |
||
132 | jmp .next_socket |
||
133 | |||
134 | .decrement_tcb: |
||
1 | ha | 135 | ; decrement it, delete socket if TCB timer = 0 & socket in timewait state |
914 | serge | 136 | dec [ebx + SOCKET.TCBTimer] |
137 | jnz .next_socket |
||
1 | ha | 138 | |
914 | serge | 139 | cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
140 | jne .next_socket |
||
1 | ha | 141 | |
914 | serge | 142 | push [ebx + SOCKET.PrevPtr] |
143 | stdcall net_socket_free, ebx |
||
144 | pop ebx |
||
145 | jmp .next_socket |
||
1 | ha | 146 | |
914 | serge | 147 | .decrement_wnd: |
1 | ha | 148 | ; TODO - prove it works! |
914 | serge | 149 | dec [ebx + SOCKET.wndsizeTimer] |
150 | jmp .next_socket |
||
1 | ha | 151 | |
914 | serge | 152 | .exit: |
1 | ha | 153 | ret |
914 | serge | 154 | endp |
1 | ha | 155 | |
156 | |||
157 | ;*************************************************************************** |
||
158 | ; Function |
||
159 | ; tcp_tx_handler |
||
160 | ; |
||
161 | ; Description |
||
162 | ; Handles queued TCP data |
||
163 | ; This is a kernel function, called by stack_handler |
||
164 | ; |
||
165 | ;*************************************************************************** |
||
914 | serge | 166 | |
167 | proc tcp_tx_handler stdcall |
||
1 | ha | 168 | ; decrement all resend buffers timers. If they |
169 | ; expire, queue them for sending, and restart the timer. |
||
170 | ; If the retries counter reach 0, delete the entry |
||
171 | |||
172 | mov esi, resendQ |
||
173 | mov ecx, 0 |
||
174 | |||
914 | serge | 175 | .next_resendq: |
1 | ha | 176 | cmp ecx, NUMRESENDENTRIES |
914 | serge | 177 | je .exit ; None left |
178 | cmp dword[esi + 4], 0 |
||
179 | jne @f ; found one |
||
1 | ha | 180 | inc ecx |
914 | serge | 181 | add esi, 8 |
182 | jmp .next_resendq |
||
1 | ha | 183 | |
914 | serge | 184 | @@: ; we have one. decrement it's timer by 1 |
185 | dec word[esi + 2] |
||
186 | jz @f |
||
1 | ha | 187 | inc ecx |
914 | serge | 188 | add esi, 8 |
189 | jmp .next_resendq ; Timer not zero, so move on |
||
1 | ha | 190 | |
914 | serge | 191 | @@: |
192 | xor ebx, ebx |
||
1 | ha | 193 | ; restart timer, and decrement retries |
194 | ; After the first resend, back of on next, by a factor of 5 |
||
914 | serge | 195 | mov [esi + 2], word TCP_TIMEOUT * 5 |
196 | dec byte[esi + 1] |
||
197 | jnz @f |
||
1 | ha | 198 | |
199 | ; retries now 0, so delete from queue |
||
914 | serge | 200 | xchg [esi + 4], ebx |
1 | ha | 201 | |
914 | serge | 202 | @@: ; resend packet |
203 | pushad |
||
1 | ha | 204 | |
205 | mov eax, EMPTY_QUEUE |
||
206 | call dequeue |
||
207 | cmp ax, NO_BUFFER |
||
914 | serge | 208 | jne .tth004z |
1 | ha | 209 | |
210 | ; TODO - try again in 10ms. |
||
914 | serge | 211 | test ebx, ebx |
212 | jnz @f |
||
213 | mov [esi + 4], ebx |
||
1 | ha | 214 | |
914 | serge | 215 | @@: ; Mark it to expire in 10ms - 1 tick |
216 | mov byte[esi + 1], 1 |
||
217 | mov word[esi + 2], 1 |
||
218 | jmp .tth005 |
||
1 | ha | 219 | |
914 | serge | 220 | .tth004z: |
1 | ha | 221 | ; we have a buffer # in ax |
222 | |||
914 | serge | 223 | push eax ecx |
1 | ha | 224 | mov ecx, IPBUFFSIZE |
225 | mul ecx |
||
226 | add eax, IPbuffs |
||
227 | |||
228 | ; we have the buffer address in eax |
||
229 | mov edi, eax |
||
230 | pop ecx |
||
231 | ; Now get buffer location, and copy buffer across. argh! more copying,, |
||
914 | serge | 232 | mov esi, resendBuffer |
233 | @@: add esi, IPBUFFSIZE |
||
234 | loop @b |
||
1 | ha | 235 | |
236 | ; we have resend buffer location in esi |
||
237 | mov ecx, IPBUFFSIZE |
||
238 | |||
239 | ; copy data across |
||
914 | serge | 240 | push edi |
1 | ha | 241 | cld |
242 | rep movsb |
||
914 | serge | 243 | pop edi |
1 | ha | 244 | |
245 | ; queue packet |
||
246 | |||
247 | |||
248 | |||
249 | mov eax, NET1OUT_QUEUE |
||
250 | |||
251 | mov edx, [stack_ip] |
||
914 | serge | 252 | cmp edx, [edi + IP_PACKET.DestinationAddress] |
253 | jne .not_local |
||
1 | ha | 254 | mov eax, IPIN_QUEUE |
255 | |||
914 | serge | 256 | .not_local: |
1 | ha | 257 | pop ebx |
258 | |||
259 | call queue |
||
260 | |||
914 | serge | 261 | .tth005: |
262 | popad |
||
1 | ha | 263 | |
264 | inc ecx |
||
914 | serge | 265 | add esi, 8 |
266 | jmp .next_resendq |
||
1 | ha | 267 | |
914 | serge | 268 | .exit: |
1 | ha | 269 | ret |
914 | serge | 270 | endp |
1 | ha | 271 | |
272 | |||
273 | ;*************************************************************************** |
||
274 | ; Function |
||
275 | ; tcp_rx |
||
276 | ; |
||
277 | ; Description |
||
278 | ; TCP protocol handler |
||
279 | ; This is a kernel function, called by ip_rx |
||
280 | ; IP buffer address given in edx |
||
281 | ; IP buffer number in eax |
||
282 | ; Free up (or re-use) IP buffer when finished |
||
283 | ; |
||
284 | ;*************************************************************************** |
||
914 | serge | 285 | |
286 | proc tcp_rx stdcall uses ebx |
||
1 | ha | 287 | ; The process is as follows. |
288 | ; Look for a socket with matching remote IP, remote port, local port |
||
289 | ; if not found, then |
||
290 | ; look for remote IP + local port match ( where sockets remote port = 0) |
||
291 | ; if not found, then |
||
292 | ; look for a socket where local socket port == IP packets remote port |
||
293 | ; where sockets remote port, remote IP = 0 |
||
294 | ; discard if not found |
||
295 | ; Call sockets tcbStateMachine, with pointer to packet. |
||
296 | ; the state machine will not delete the packet, so do that here. |
||
297 | |||
298 | push eax |
||
299 | |||
300 | ; Look for a socket where |
||
301 | ; IP Packet TCP Destination Port = local Port |
||
302 | ; IP Packet SA = Remote IP |
||
303 | ; IP Packet TCP Source Port = remote Port |
||
304 | |||
914 | serge | 305 | mov ebx, net_sockets |
1 | ha | 306 | |
914 | serge | 307 | .next_socket.1: |
308 | mov ebx, [ebx + SOCKET.NextPtr] |
||
309 | or ebx, ebx |
||
310 | jz .next_socket.1.exit |
||
1 | ha | 311 | |
914 | serge | 312 | ; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
1 | ha | 313 | |
914 | serge | 314 | mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr |
315 | cmp [ebx + SOCKET.LocalPort], ax ; get the dest. port from the TCP hdr |
||
316 | jne .next_socket.1 ; different - try next socket |
||
317 | |||
318 | ; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
||
319 | |||
320 | mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr |
||
321 | cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP |
||
322 | jne .next_socket.1 ; different - try next socket |
||
323 | |||
324 | ; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4 |
||
325 | |||
326 | mov ax, [edx + 20 + TCP_PACKET.SourcePort] ; get the source port from the TCP hdr |
||
327 | cmp [ebx + SOCKET.RemotePort], ax ; compare with socket's remote port |
||
328 | jne .next_socket.1 ; different - try next socket |
||
329 | |||
1 | ha | 330 | ; We have a complete match - use this socket |
914 | serge | 331 | jmp .change_state |
1 | ha | 332 | |
914 | serge | 333 | .next_socket.1.exit: |
1 | ha | 334 | |
335 | ; If we got here, there was no match |
||
336 | ; Look for a socket where |
||
337 | ; IP Packet TCP Destination Port = local Port |
||
338 | ; IP Packet SA = Remote IP |
||
339 | ; socket remote Port = 0 |
||
340 | |||
914 | serge | 341 | mov ebx, net_sockets |
1 | ha | 342 | |
914 | serge | 343 | .next_socket.2: |
344 | mov ebx, [ebx + SOCKET.NextPtr] |
||
345 | or ebx, ebx |
||
346 | jz .next_socket.2.exit |
||
1 | ha | 347 | |
914 | serge | 348 | ; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
1 | ha | 349 | |
914 | serge | 350 | mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr |
351 | cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port |
||
352 | jne .next_socket.2 ; different - try next socket |
||
1 | ha | 353 | |
914 | serge | 354 | ; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
355 | |||
356 | mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr |
||
357 | cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP |
||
358 | jne .next_socket.2 ; different - try next socket |
||
359 | |||
360 | ; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 |
||
361 | |||
362 | cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 |
||
363 | jne .next_socket.2 ; different - try next socket |
||
364 | |||
1 | ha | 365 | ; We have a complete match - use this socket |
914 | serge | 366 | jmp .change_state |
1 | ha | 367 | |
914 | serge | 368 | .next_socket.2.exit: |
1 | ha | 369 | |
370 | ; If we got here, there was no match |
||
371 | ; Look for a socket where |
||
372 | ; IP Packet TCP Destination Port = local Port |
||
373 | ; socket Remote IP = 0 |
||
374 | ; socket remote Port = 0 |
||
375 | |||
914 | serge | 376 | mov ebx, net_sockets |
1 | ha | 377 | |
914 | serge | 378 | .next_socket.3: |
379 | mov ebx, [ebx + SOCKET.NextPtr] |
||
380 | or ebx, ebx |
||
381 | jz .next_socket.3.exit |
||
1 | ha | 382 | |
914 | serge | 383 | ; DEBUGF 1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
1 | ha | 384 | |
914 | serge | 385 | mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get destination port from the TCP hdr |
386 | cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port |
||
387 | jne .next_socket.3 ; different - try next socket |
||
1 | ha | 388 | |
914 | serge | 389 | ; DEBUGF 1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP] |
390 | |||
391 | cmp [ebx + SOCKET.RemoteIP], 0 ; only match a socket remote IP of 0 |
||
392 | jne .next_socket.3 ; different - try next socket |
||
393 | |||
394 | ; DEBUGF 1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 |
||
395 | |||
396 | cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 |
||
397 | jne .next_socket.3 ; different - try next socket |
||
398 | |||
1 | ha | 399 | ; We have a complete match - use this socket |
914 | serge | 400 | jmp .change_state |
1 | ha | 401 | |
914 | serge | 402 | .next_socket.3.exit: |
1 | ha | 403 | |
404 | ; If we got here, we need to reject the packet |
||
405 | |||
914 | serge | 406 | DEBUGF 1, "K : tcp_rx - dumped\n" |
407 | DEBUGF 1, "K : --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2 |
||
2971 | Serge | 408 | |
914 | serge | 409 | inc [dumped_rx_count] |
410 | jmp .exit |
||
411 | |||
412 | .change_state: |
||
413 | |||
1 | ha | 414 | ; We have a valid socket/TCB, so call the TCB State Machine for that skt. |
914 | serge | 415 | ; socket is pointed to by ebx |
416 | ; IP packet is pointed to by edx |
||
1 | ha | 417 | ; IP buffer number is on stack ( it will be popped at the end) |
418 | |||
914 | serge | 419 | stdcall tcpStateMachine, ebx |
420 | |||
421 | .exit: |
||
1 | ha | 422 | pop eax |
423 | call freeBuff |
||
424 | |||
425 | ret |
||
914 | serge | 426 | endp |
1 | ha | 427 | |
428 | |||
429 | ;*************************************************************************** |
||
430 | ; Function |
||
431 | ; buildTCPPacket |
||
432 | ; |
||
433 | ; Description |
||
434 | ; builds an IP Packet with TCP data fully populated for transmission |
||
435 | ; You may destroy any and all registers |
||
436 | ; TCP control flags specified in bl |
||
437 | ; This TCB is in [sktAddr] |
||
438 | ; User data pointed to by esi |
||
439 | ; Data length in ecx |
||
440 | ; Transmit buffer number in eax |
||
441 | ; |
||
442 | ;*************************************************************************** |
||
914 | serge | 443 | |
444 | proc build_tcp_packet stdcall, sockAddr:DWORD |
||
1 | ha | 445 | push ecx ; Save data length |
446 | |||
447 | ; convert buffer pointer eax to the absolute address |
||
448 | mov ecx, IPBUFFSIZE |
||
449 | mul ecx |
||
450 | add eax, IPbuffs |
||
451 | |||
452 | mov edx, eax |
||
453 | |||
914 | serge | 454 | mov [edx + 20 + TCP_PACKET.Flags], bl ; TCP flags |
1 | ha | 455 | |
914 | serge | 456 | mov ebx, [sockAddr] |
1 | ha | 457 | |
458 | ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr |
||
459 | |||
460 | ; Fill in the IP header ( some data is in the socket descriptor) |
||
914 | serge | 461 | mov eax, [ebx + SOCKET.LocalIP] |
462 | mov [edx + IP_PACKET.SourceAddress], eax |
||
463 | mov eax, [ebx + SOCKET.RemoteIP] |
||
464 | mov [edx + IP_PACKET.DestinationAddress], eax |
||
1 | ha | 465 | |
914 | serge | 466 | mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
467 | mov [edx + IP_PACKET.TypeOfService], 0 |
||
1 | ha | 468 | |
469 | pop eax ; Get the TCP data length |
||
470 | push eax |
||
471 | |||
472 | add eax, 20 + 20 ; add IP header and TCP header lengths |
||
914 | serge | 473 | rol ax, 8 |
474 | mov [edx + IP_PACKET.TotalLength], ax |
||
475 | mov [edx + IP_PACKET.Identification], 0 |
||
476 | mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
||
477 | mov [edx + IP_PACKET.TimeToLive], 0x20 |
||
478 | mov [edx + IP_PACKET.Protocol], PROTOCOL_TCP |
||
1 | ha | 479 | |
480 | ; Checksum left unfilled |
||
914 | serge | 481 | mov [edx + IP_PACKET.HeaderChecksum], 0 |
1 | ha | 482 | |
914 | serge | 483 | ; Fill in the TCP header (some data is in the socket descriptor) |
484 | mov ax, [ebx + SOCKET.LocalPort] |
||
485 | mov [edx + 20 + TCP_PACKET.SourcePort], ax ; Local Port |
||
1 | ha | 486 | |
914 | serge | 487 | mov ax, [ebx + SOCKET.RemotePort] |
488 | mov [edx + 20 + TCP_PACKET.DestinationPort], ax ; desitination Port |
||
1 | ha | 489 | |
490 | ; Checksum left unfilled |
||
914 | serge | 491 | mov [edx + 20 + TCP_PACKET.Checksum], 0 |
1 | ha | 492 | |
493 | ; sequence number |
||
914 | serge | 494 | mov eax, [ebx + SOCKET.SND_NXT] |
495 | mov [edx + 20 + TCP_PACKET.SequenceNumber], eax |
||
1 | ha | 496 | |
497 | ; ack number |
||
914 | serge | 498 | mov eax, [ebx + SOCKET.RCV_NXT] |
499 | mov [edx + 20 + TCP_PACKET.AckNumber], eax |
||
1 | ha | 500 | |
501 | ; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size) |
||
502 | ; 768 bytes seems better |
||
914 | serge | 503 | mov [edx + 20 + TCP_PACKET.Window], 0x0003 |
1 | ha | 504 | |
505 | ; Urgent pointer (0) |
||
914 | serge | 506 | mov [edx + 20 + TCP_PACKET.UrgentPointer], 0 |
1 | ha | 507 | |
508 | ; data offset ( 0x50 ) |
||
914 | serge | 509 | mov [edx + 20 + TCP_PACKET.DataOffset], 0x50 |
1 | ha | 510 | |
511 | pop ecx ; count of bytes to send |
||
512 | mov ebx, ecx ; need the length later |
||
513 | |||
514 | cmp ebx, 0 |
||
914 | serge | 515 | jz @f |
1 | ha | 516 | |
517 | mov edi, edx |
||
518 | add edi, 40 |
||
519 | cld |
||
520 | rep movsb ; copy the data across |
||
521 | |||
914 | serge | 522 | @@: ; we have edx as IPbuffer ptr. |
1 | ha | 523 | ; Fill in the TCP checksum |
524 | ; First, fill in pseudoheader |
||
914 | serge | 525 | mov eax, [edx + IP_PACKET.SourceAddress] |
1 | ha | 526 | mov [pseudoHeader], eax |
914 | serge | 527 | mov eax, [edx + IP_PACKET.DestinationAddress] |
528 | mov [pseudoHeader + 4], eax |
||
529 | mov word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0 |
||
1 | ha | 530 | add ebx, 20 |
914 | serge | 531 | mov [pseudoHeader + 10], bh |
532 | mov [pseudoHeader + 11], bl |
||
1 | ha | 533 | |
534 | mov eax, pseudoHeader |
||
535 | mov [checkAdd1], eax |
||
914 | serge | 536 | mov word[checkSize1], 12 |
1 | ha | 537 | mov eax, edx |
538 | add eax, 20 |
||
539 | mov [checkAdd2], eax |
||
540 | mov eax, ebx |
||
541 | mov [checkSize2], ax |
||
542 | |||
543 | call checksum |
||
544 | |||
545 | ; store it in the TCP checksum ( in the correct order! ) |
||
546 | mov ax, [checkResult] |
||
914 | serge | 547 | rol ax, 8 |
548 | mov [edx + 20 + TCP_PACKET.Checksum], ax |
||
1 | ha | 549 | |
550 | ; Fill in the IP header checksum |
||
914 | serge | 551 | GET_IHL eax, edx ; get IP-Header length |
552 | stdcall checksum_jb, edx, eax ; buf_ptr, buf_size |
||
553 | rol ax, 8 |
||
554 | mov [edx + IP_PACKET.HeaderChecksum], ax |
||
1 | ha | 555 | |
556 | ret |
||
914 | serge | 557 | endp |
1 | ha | 558 | |
559 | |||
560 | ; Increments the 32 bit value pointed to by esi in internet order |
||
914 | serge | 561 | proc inc_inet_esi stdcall |
1 | ha | 562 | push eax |
914 | serge | 563 | mov eax, [esi] |
564 | bswap eax |
||
565 | inc eax |
||
566 | bswap eax |
||
567 | mov [esi], eax |
||
1 | ha | 568 | pop eax |
569 | ret |
||
914 | serge | 570 | endp |
1 | ha | 571 | |
572 | |||
573 | ; Increments the 32 bit value pointed to by esi in internet order |
||
574 | ; by the value in ecx |
||
914 | serge | 575 | proc add_inet_esi stdcall |
1 | ha | 576 | push eax |
914 | serge | 577 | mov eax, [esi] |
578 | bswap eax |
||
1 | ha | 579 | add eax, ecx |
914 | serge | 580 | bswap eax |
581 | mov [esi], eax |
||
1 | ha | 582 | pop eax |
583 | ret |
||
914 | serge | 584 | endp |
1 | ha | 585 | |
586 | |||
587 | iglobal |
||
914 | serge | 588 | TCBStateHandler dd \ |
589 | stateTCB_LISTEN, \ |
||
590 | stateTCB_SYN_SENT, \ |
||
591 | stateTCB_SYN_RECEIVED, \ |
||
592 | stateTCB_ESTABLISHED, \ |
||
593 | stateTCB_FIN_WAIT_1, \ |
||
594 | stateTCB_FIN_WAIT_2, \ |
||
595 | stateTCB_CLOSE_WAIT, \ |
||
596 | stateTCB_CLOSING, \ |
||
597 | stateTCB_LAST_ACK, \ |
||
598 | stateTCB_TIME_WAIT, \ |
||
599 | stateTCB_CLOSED |
||
1 | ha | 600 | endg |
601 | |||
602 | ;*************************************************************************** |
||
603 | ; Function |
||
604 | ; tcpStateMachine |
||
605 | ; |
||
606 | ; Description |
||
607 | ; TCP state machine |
||
608 | ; This is a kernel function, called by tcp_rx |
||
609 | ; |
||
610 | ; IP buffer address given in edx |
||
914 | serge | 611 | ; Socket/TCB address in ebx |
1 | ha | 612 | ; |
613 | ; The IP buffer will be released by the caller |
||
614 | ;*************************************************************************** |
||
615 | |||
914 | serge | 616 | proc tcpStateMachine stdcall, sockAddr:DWORD |
1 | ha | 617 | ; as a packet has been received, update the TCB timer |
914 | serge | 618 | mov [ebx + SOCKET.TCBTimer], TWOMSL |
1 | ha | 619 | |
620 | ; If the received packet has an ACK bit set, |
||
621 | ; remove any packets in the resend queue that this |
||
622 | ; received packet acknowledges |
||
914 | serge | 623 | pushad |
624 | test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
||
625 | jz .call_handler ; No ACK, so no data yet |
||
1 | ha | 626 | |
914 | serge | 627 | ; get skt number in eax |
628 | stdcall net_socket_addr_to_num, ebx |
||
1 | ha | 629 | |
630 | ; The ack number is in [edx + 28], inet format |
||
914 | serge | 631 | ; skt in eax |
1 | ha | 632 | |
633 | mov esi, resendQ |
||
914 | serge | 634 | xor ecx, ecx |
1 | ha | 635 | |
914 | serge | 636 | .next_resendq: |
1 | ha | 637 | cmp ecx, NUMRESENDENTRIES |
914 | serge | 638 | je .call_handler ; None left |
639 | cmp [esi + 4], eax |
||
640 | je @f ; found one |
||
1 | ha | 641 | inc ecx |
914 | serge | 642 | add esi, 8 |
643 | jmp .next_resendq |
||
1 | ha | 644 | |
914 | serge | 645 | @@: ; Can we delete this buffer? |
1 | ha | 646 | |
914 | serge | 647 | ; If yes, goto @@. No, goto .next_resendq |
1 | ha | 648 | ; Get packet data address |
649 | |||
650 | push ecx |
||
651 | ; Now get buffer location, and copy buffer across. argh! more copying,, |
||
914 | serge | 652 | imul edi, ecx, IPBUFFSIZE |
653 | add edi, resendBuffer |
||
1 | ha | 654 | |
655 | ; we have dest buffer location in edi. incoming packet in edx. |
||
656 | ; Get this packets sequence number |
||
657 | ; preserve al, ecx, esi, edx |
||
914 | serge | 658 | mov ecx, [edi + 20 + TCP_PACKET.SequenceNumber] |
659 | bswap ecx |
||
660 | movzx ebx, word[edi + 2] |
||
661 | xchg bl, bh |
||
1 | ha | 662 | sub ebx, 40 |
663 | add ecx, ebx ; ecx is now seq# of last byte +1, intel format |
||
664 | |||
665 | ; get recievd ack #, in intel format |
||
914 | serge | 666 | mov ebx, [edx + 20 + TCP_PACKET.AckNumber] |
667 | bswap ebx |
||
1 | ha | 668 | |
669 | cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que |
||
670 | ; DANGER! need to handle case that we have just |
||
671 | ; passed the 2**32, and wrapped round! |
||
672 | pop ecx |
||
914 | serge | 673 | jae @f ; if rx > old, delete old |
1 | ha | 674 | |
675 | inc ecx |
||
914 | serge | 676 | add esi, 8 |
677 | jmp .next_resendq |
||
1 | ha | 678 | |
914 | serge | 679 | @@: mov dword[esi + 4], 0 |
1 | ha | 680 | inc ecx |
914 | serge | 681 | add esi, 8 |
682 | jmp .next_resendq |
||
1 | ha | 683 | |
914 | serge | 684 | .call_handler: |
685 | popad |
||
1 | ha | 686 | |
2971 | Serge | 687 | ; Call handler for given TCB state |
1 | ha | 688 | |
914 | serge | 689 | mov eax, [ebx + SOCKET.TCBState] |
690 | cmp eax, TCB_LISTEN |
||
691 | jb .exit |
||
692 | cmp eax, TCB_CLOSED |
||
693 | ja .exit |
||
1 | ha | 694 | |
914 | serge | 695 | stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr] |
1 | ha | 696 | |
914 | serge | 697 | .exit: |
1 | ha | 698 | ret |
914 | serge | 699 | endp |
1 | ha | 700 | |
701 | |||
914 | serge | 702 | proc stateTCB_LISTEN stdcall, sockAddr:DWORD |
1 | ha | 703 | ; In this case, we are expecting a SYN packet |
704 | ; For now, if the packet is a SYN, process it, and send a response |
||
705 | ; If not, ignore it |
||
706 | |||
707 | ; Look at control flags |
||
914 | serge | 708 | test [edx + 20 + TCP_PACKET.Flags], TH_SYN |
709 | jz .exit |
||
1 | ha | 710 | |
711 | ; We have a SYN. update the socket with this IP packets details, |
||
712 | ; And send a response |
||
713 | |||
914 | serge | 714 | mov eax, [edx + IP_PACKET.SourceAddress] |
715 | mov [ebx + SOCKET.RemoteIP], eax |
||
716 | mov ax, [edx + 20 + TCP_PACKET.SourcePort] |
||
717 | mov [ebx + SOCKET.RemotePort], ax |
||
718 | mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
||
719 | mov [ebx + SOCKET.IRS], eax |
||
720 | mov [ebx + SOCKET.RCV_NXT], eax |
||
721 | lea esi, [ebx + SOCKET.RCV_NXT] |
||
1 | ha | 722 | call inc_inet_esi ; RCV.NXT |
914 | serge | 723 | mov eax, [ebx + SOCKET.ISS] |
724 | mov [ebx + SOCKET.SND_NXT], eax |
||
1 | ha | 725 | |
726 | ; Now construct the response, and queue for sending by IP |
||
727 | mov eax, EMPTY_QUEUE |
||
728 | call dequeue |
||
729 | cmp ax, NO_BUFFER |
||
914 | serge | 730 | je .exit |
1 | ha | 731 | |
732 | push eax |
||
914 | serge | 733 | mov bl, TH_SYN + TH_ACK |
734 | xor ecx, ecx |
||
735 | xor esi, esi |
||
736 | stdcall build_tcp_packet, [sockAddr] |
||
1 | ha | 737 | |
738 | mov eax, NET1OUT_QUEUE |
||
739 | mov edx, [stack_ip] |
||
914 | serge | 740 | mov ecx, [sockAddr] |
741 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
742 | jne .not_local |
||
1 | ha | 743 | mov eax, IPIN_QUEUE |
744 | |||
914 | serge | 745 | .not_local: |
1 | ha | 746 | ; Send it. |
747 | pop ebx |
||
748 | call queue |
||
749 | |||
914 | serge | 750 | mov esi, [sockAddr] |
751 | mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED |
||
1 | ha | 752 | |
914 | serge | 753 | ; increment SND.NXT in socket |
754 | add esi, SOCKET.SND_NXT |
||
1 | ha | 755 | call inc_inet_esi |
756 | |||
914 | serge | 757 | .exit: |
1 | ha | 758 | ret |
914 | serge | 759 | endp |
1 | ha | 760 | |
761 | |||
914 | serge | 762 | proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD |
1 | ha | 763 | ; We are awaiting an ACK to our SYN, with a SYM |
764 | ; Look at control flags - expecting an ACK |
||
765 | |||
914 | serge | 766 | mov al, [edx + 20 + TCP_PACKET.Flags] |
767 | and al, TH_SYN + TH_ACK |
||
768 | cmp al, TH_SYN + TH_ACK |
||
769 | je .syn_ack |
||
1 | ha | 770 | |
914 | serge | 771 | test al, TH_SYN |
772 | jz .exit |
||
773 | |||
774 | mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED |
||
775 | push TH_SYN + TH_ACK |
||
776 | jmp .send |
||
777 | |||
778 | .syn_ack: |
||
779 | mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
||
780 | push TH_ACK |
||
781 | |||
782 | .send: |
||
1 | ha | 783 | ; Store the recv.nxt field |
914 | serge | 784 | mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
1 | ha | 785 | |
786 | ; Update our recv.nxt field |
||
914 | serge | 787 | mov [ebx + SOCKET.RCV_NXT], eax |
788 | lea esi, [ebx + SOCKET.RCV_NXT] |
||
1 | ha | 789 | call inc_inet_esi |
790 | |||
791 | ; Send an ACK |
||
792 | ; Now construct the response, and queue for sending by IP |
||
793 | mov eax, EMPTY_QUEUE |
||
794 | call dequeue |
||
795 | cmp ax, NO_BUFFER |
||
914 | serge | 796 | pop ebx |
797 | je .exit |
||
1 | ha | 798 | |
799 | push eax |
||
800 | |||
914 | serge | 801 | xor ecx, ecx |
802 | xor esi, esi |
||
803 | stdcall build_tcp_packet, [sockAddr] |
||
1 | ha | 804 | |
805 | mov eax, NET1OUT_QUEUE |
||
806 | |||
807 | mov edx, [stack_ip] |
||
914 | serge | 808 | mov ecx, [sockAddr] |
809 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
810 | jne .not_local |
||
1 | ha | 811 | mov eax, IPIN_QUEUE |
812 | |||
914 | serge | 813 | .not_local: |
1 | ha | 814 | ; Send it. |
815 | pop ebx |
||
816 | call queue |
||
817 | |||
914 | serge | 818 | .exit: |
1 | ha | 819 | ret |
914 | serge | 820 | endp |
1 | ha | 821 | |
822 | |||
914 | serge | 823 | proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD |
1 | ha | 824 | ; In this case, we are expecting an ACK packet |
825 | ; For now, if the packet is an ACK, process it, |
||
826 | ; If not, ignore it |
||
827 | |||
2971 | Serge | 828 | test [edx + 20 + TCP_PACKET.Flags], TH_RST |
829 | jz .check_ack |
||
914 | serge | 830 | |
831 | push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP] |
||
832 | pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort] |
||
833 | |||
2971 | Serge | 834 | mov [ebx + SOCKET.TCBState], TCB_LISTEN |
835 | jmp .exit |
||
914 | serge | 836 | |
2971 | Serge | 837 | .check_ack: |
1 | ha | 838 | ; Look at control flags - expecting an ACK |
914 | serge | 839 | test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
840 | jz .exit |
||
1 | ha | 841 | |
914 | serge | 842 | mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
1 | ha | 843 | |
914 | serge | 844 | .exit: |
1 | ha | 845 | ret |
914 | serge | 846 | endp |
1 | ha | 847 | |
848 | |||
914 | serge | 849 | proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD |
1 | ha | 850 | ; Here we are expecting data, or a request to close |
851 | ; OR both... |
||
852 | |||
853 | ; Did we receive a FIN or RST? |
||
2971 | Serge | 854 | test [edx + 20 + TCP_PACKET.Flags], TH_FIN |
855 | jz .check_ack |
||
1 | ha | 856 | |
857 | ; It was a fin or reset. |
||
858 | |||
859 | ; Remove resend entries from the queue - I dont want to send any more data |
||
914 | serge | 860 | pushad |
1 | ha | 861 | |
914 | serge | 862 | ; get skt # |
863 | stdcall net_socket_addr_to_num, ebx |
||
1 | ha | 864 | |
865 | mov esi, resendQ |
||
866 | mov ecx, 0 |
||
867 | |||
914 | serge | 868 | .next_resendq: |
1 | ha | 869 | cmp ecx, NUMRESENDENTRIES |
914 | serge | 870 | je .last_resendq ; None left |
871 | cmp [esi + 4], eax |
||
872 | je @f ; found one |
||
873 | inc ecx |
||
874 | add esi, 8 |
||
875 | jmp .next_resendq |
||
876 | |||
877 | @@: mov dword[esi + 4], 0 |
||
1 | ha | 878 | inc ecx |
914 | serge | 879 | add esi, 8 |
880 | jmp .next_resendq |
||
1 | ha | 881 | |
914 | serge | 882 | .last_resendq: |
883 | popad |
||
1 | ha | 884 | |
914 | serge | 885 | @@: ; Send an ACK to that fin, and enter closewait state |
1 | ha | 886 | |
914 | serge | 887 | mov [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
888 | lea esi, [ebx + SOCKET.RCV_NXT] |
||
1 | ha | 889 | mov eax, [esi] ; save original |
890 | call inc_inet_esi |
||
891 | ;; jmp ste_ack - NO, there may be data |
||
892 | |||
914 | serge | 893 | .check_ack: |
1 | ha | 894 | ; Check that we received an ACK |
914 | serge | 895 | test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
896 | jz .exit |
||
1 | ha | 897 | |
898 | ; TODO - done, I think! |
||
899 | ; First, look at the incoming window. If this is less than or equal to 1024, |
||
914 | serge | 900 | ; Set the socket window timer to 1. This will stop an additional packets being queued. |
1 | ha | 901 | ; ** I may need to tweak this value, since I do not know how many packets are already queued |
914 | serge | 902 | mov cx, [edx + 20 + TCP_PACKET.Window] |
903 | xchg cl, ch |
||
1 | ha | 904 | cmp cx, 1024 |
914 | serge | 905 | ja @f |
1 | ha | 906 | |
914 | serge | 907 | mov [ebx + SOCKET.wndsizeTimer], 1 |
1 | ha | 908 | |
914 | serge | 909 | @@: ; OK, here is the deal |
1 | ha | 910 | ; My recv.nct field holds the seq of the expected next rec byte |
911 | ; if the recevied sequence number is not equal to this, do not |
||
912 | ; increment the recv.nxt field, do not copy data - just send a |
||
913 | ; repeat ack. |
||
914 | |||
914 | serge | 915 | ; recv.nxt is in dword [edx+24], in inet format |
1 | ha | 916 | ; recv seq is in [sktAddr]+56, in inet format |
917 | ; just do a comparision |
||
914 | serge | 918 | mov ecx, [ebx + SOCKET.RCV_NXT] |
919 | cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
||
920 | jne @f |
||
1 | ha | 921 | mov ecx, eax |
922 | |||
914 | serge | 923 | @@: cmp ecx, [edx + 20 + TCP_PACKET.SequenceNumber] |
924 | jne .ack |
||
1 | ha | 925 | |
926 | |||
927 | ; Read the data bytes, store in socket buffer |
||
914 | serge | 928 | movzx ecx, [edx + IP_PACKET.TotalLength] |
929 | xchg cl, ch |
||
1 | ha | 930 | sub ecx, 40 ; Discard 40 bytes of header |
2971 | Serge | 931 | ja .data ; Read data, if any |
1 | ha | 932 | |
933 | ; If we had received a fin, we need to ACK it. |
||
914 | serge | 934 | cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
935 | je .ack |
||
936 | jmp .exit |
||
1 | ha | 937 | |
914 | serge | 938 | .data: |
2971 | Serge | 939 | push ebx |
940 | add ebx, SOCKET.lock |
||
941 | call wait_mutex |
||
942 | pop ebx |
||
1 | ha | 943 | |
2971 | Serge | 944 | push ecx |
945 | push [ebx + SOCKET.PID] ; get socket owner PID |
||
946 | mov eax, [ebx + SOCKET.rxDataCount] |
||
947 | add eax, ecx |
||
948 | cmp eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE |
||
949 | ja .overflow |
||
1 | ha | 950 | |
2971 | Serge | 951 | mov [ebx + SOCKET.rxDataCount], eax ; increment the count of bytes in buffer |
1 | ha | 952 | |
953 | ; point to the location to store the data |
||
914 | serge | 954 | lea edi, [ebx + eax + SOCKETHEADERSIZE] |
955 | sub edi, ecx |
||
1 | ha | 956 | |
957 | add edx, 40 ; edx now points to the data |
||
958 | mov esi, edx |
||
959 | |||
960 | cld |
||
961 | rep movsb ; copy the data across |
||
2971 | Serge | 962 | mov [ebx + SOCKET.lock], 0 ; release mutex |
1 | ha | 963 | |
964 | ; flag an event to the application |
||
965 | pop eax |
||
914 | serge | 966 | mov ecx, 1 |
967 | mov esi, TASK_DATA + TASKDATA.pid |
||
1 | ha | 968 | |
914 | serge | 969 | .next_pid: |
970 | cmp [esi], eax |
||
971 | je .found_pid |
||
1 | ha | 972 | inc ecx |
914 | serge | 973 | add esi, 0x20 |
974 | cmp ecx, [TASK_COUNT] |
||
975 | jbe .next_pid |
||
1 | ha | 976 | |
914 | serge | 977 | .found_pid: |
978 | shl ecx, 8 |
||
979 | or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
||
1 | ha | 980 | |
981 | pop ecx |
||
982 | |||
983 | ; Update our recv.nxt field |
||
914 | serge | 984 | lea esi, [ebx + SOCKET.RCV_NXT] |
1 | ha | 985 | call add_inet_esi |
986 | |||
914 | serge | 987 | .ack: |
1 | ha | 988 | ; Send an ACK |
989 | ; Now construct the response, and queue for sending by IP |
||
990 | mov eax, EMPTY_QUEUE |
||
991 | call dequeue |
||
992 | cmp ax, NO_BUFFER |
||
914 | serge | 993 | je .exit |
1 | ha | 994 | |
995 | push eax |
||
996 | |||
914 | serge | 997 | mov bl, TH_ACK |
998 | xor ecx, ecx |
||
999 | xor esi, esi |
||
1000 | stdcall build_tcp_packet, [sockAddr] |
||
1 | ha | 1001 | |
1002 | mov eax, NET1OUT_QUEUE |
||
1003 | |||
1004 | mov edx, [stack_ip] |
||
914 | serge | 1005 | mov ecx, [sockAddr] |
1006 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
1007 | jne .not_local |
||
1 | ha | 1008 | mov eax, IPIN_QUEUE |
1009 | |||
914 | serge | 1010 | .not_local: |
1 | ha | 1011 | ; Send it. |
1012 | pop ebx |
||
1013 | call queue |
||
1014 | |||
914 | serge | 1015 | .exit: |
1 | ha | 1016 | ret |
2971 | Serge | 1017 | .overflow: |
1018 | ; no place in buffer |
||
1019 | ; so simply restore stack and exit |
||
1020 | pop eax ecx |
||
1021 | mov [ebx + SOCKET.lock], 0 |
||
1022 | ret |
||
914 | serge | 1023 | endp |
1 | ha | 1024 | |
1025 | |||
914 | serge | 1026 | proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD |
2971 | Serge | 1027 | ; We can either receive an ACK of a fin, or a fin |
914 | serge | 1028 | mov al, [edx + 20 + TCP_PACKET.Flags] |
1029 | and al, TH_FIN + TH_ACK |
||
1 | ha | 1030 | |
914 | serge | 1031 | cmp al, TH_ACK |
1032 | jne @f |
||
1 | ha | 1033 | |
1034 | ; It was an ACK |
||
914 | serge | 1035 | mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2 |
1036 | jmp .exit |
||
1 | ha | 1037 | |
914 | serge | 1038 | @@: mov [ebx + SOCKET.TCBState], TCB_CLOSING |
1039 | cmp al, TH_FIN |
||
1040 | je @f |
||
1041 | mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
||
1042 | |||
1043 | @@: lea esi, [ebx + SOCKET.RCV_NXT] |
||
1 | ha | 1044 | call inc_inet_esi |
1045 | |||
1046 | ; Send an ACK |
||
1047 | mov eax, EMPTY_QUEUE |
||
1048 | call dequeue |
||
1049 | cmp ax, NO_BUFFER |
||
914 | serge | 1050 | je .exit |
1 | ha | 1051 | |
1052 | push eax |
||
1053 | |||
914 | serge | 1054 | mov bl, TH_ACK |
1055 | xor ecx, ecx |
||
1056 | xor esi, esi |
||
1057 | stdcall build_tcp_packet, [sockAddr] |
||
1 | ha | 1058 | |
1059 | mov eax, NET1OUT_QUEUE |
||
1060 | |||
1061 | mov edx, [stack_ip] |
||
914 | serge | 1062 | mov ecx, [sockAddr] |
1063 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
1064 | jne .not_local |
||
1 | ha | 1065 | mov eax, IPIN_QUEUE |
1066 | |||
914 | serge | 1067 | .not_local: |
1 | ha | 1068 | ; Send it. |
1069 | pop ebx |
||
1070 | call queue |
||
1071 | |||
914 | serge | 1072 | .exit: |
1 | ha | 1073 | ret |
914 | serge | 1074 | endp |
1 | ha | 1075 | |
1076 | |||
914 | serge | 1077 | proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD |
1078 | test [edx + 20 + TCP_PACKET.Flags], TH_FIN |
||
1079 | jz .exit |
||
1 | ha | 1080 | |
1081 | ; Change state, as we have a fin |
||
914 | serge | 1082 | mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
1 | ha | 1083 | |
914 | serge | 1084 | lea esi, [ebx + SOCKET.RCV_NXT] |
1085 | call inc_inet_esi |
||
1 | ha | 1086 | |
1087 | ; Send an ACK |
||
1088 | mov eax, EMPTY_QUEUE |
||
1089 | call dequeue |
||
1090 | cmp ax, NO_BUFFER |
||
914 | serge | 1091 | je .exit |
1 | ha | 1092 | |
1093 | push eax |
||
1094 | |||
914 | serge | 1095 | mov bl, TH_ACK |
1096 | xor ecx, ecx |
||
1097 | xor esi, esi |
||
1098 | stdcall build_tcp_packet, [sockAddr] |
||
1 | ha | 1099 | |
1100 | mov eax, NET1OUT_QUEUE |
||
1101 | |||
1102 | mov edx, [stack_ip] |
||
914 | serge | 1103 | mov ecx, [sockAddr] |
1104 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
1105 | jne .not_local |
||
1 | ha | 1106 | mov eax, IPIN_QUEUE |
1107 | |||
914 | serge | 1108 | .not_local: |
1 | ha | 1109 | ; Send it. |
1110 | pop ebx |
||
1111 | call queue |
||
1112 | |||
914 | serge | 1113 | .exit: |
1 | ha | 1114 | ret |
914 | serge | 1115 | endp |
1 | ha | 1116 | |
1117 | |||
914 | serge | 1118 | proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD |
1 | ha | 1119 | ; Intentionally left empty |
1120 | ; socket_close_tcp handles this |
||
1121 | ret |
||
914 | serge | 1122 | endp |
1 | ha | 1123 | |
1124 | |||
914 | serge | 1125 | proc stateTCB_CLOSING stdcall, sockAddr:DWORD |
1 | ha | 1126 | ; We can either receive an ACK of a fin, or a fin |
914 | serge | 1127 | test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
1128 | jz .exit |
||
1 | ha | 1129 | |
914 | serge | 1130 | mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
1 | ha | 1131 | |
914 | serge | 1132 | .exit: |
1 | ha | 1133 | ret |
914 | serge | 1134 | endp |
1 | ha | 1135 | |
1136 | |||
914 | serge | 1137 | proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD |
1 | ha | 1138 | ; Look at control flags - expecting an ACK |
914 | serge | 1139 | test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
1140 | jz .exit |
||
1 | ha | 1141 | |
1142 | ; delete the socket |
||
914 | serge | 1143 | stdcall net_socket_free, ebx |
1 | ha | 1144 | |
914 | serge | 1145 | .exit: |
1 | ha | 1146 | ret |
914 | serge | 1147 | endp |
1 | ha | 1148 | |
1149 | |||
914 | serge | 1150 | proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD |
1 | ha | 1151 | ret |
914 | serge | 1152 | endp |
1 | ha | 1153 | |
1154 | |||
914 | serge | 1155 | proc stateTCB_CLOSED stdcall, sockAddr:DWORD |
1 | ha | 1156 | ret |
914 | serge | 1157 | endp |