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