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