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