Rev 1154 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
431 | serge | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
983 | diamond | 3 | ;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
431 | serge | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;; SOCKET.INC ;; |
||
7 | ;; ;; |
||
8 | ;; Sockets constants, structures and functions ;; |
||
9 | ;; ;; |
||
10 | ;; This file contains the following: ;; |
||
11 | ;; is_localport_unused ;; |
||
12 | ;; get_free_socket ;; |
||
13 | ;; socket_open ;; |
||
14 | ;; socket_open_tcp ;; |
||
15 | ;; socket_close ;; |
||
16 | ;; socket_close_tcp ;; |
||
17 | ;; socket_poll ;; |
||
18 | ;; socket_status ;; |
||
19 | ;; socket_read ;; |
||
20 | ;; socket_write ;; |
||
21 | ;; socket_write_tcp ;; |
||
22 | ;; ;; |
||
23 | ;; ;; |
||
24 | ;; Changes history: ;; |
||
25 | ;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; |
||
26 | ;; 11.11.2006 - [Johnny_B] and [smb] ;; |
||
27 | ;; ;; |
||
28 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
261 | hidnplayr | 29 | |
593 | mikedld | 30 | $Revision: 1284 $ |
31 | |||
922 | mikedld | 32 | ; socket data structure |
33 | struct SOCKET |
||
34 | .PrevPtr dd ? ; pointer to previous socket in list |
||
35 | .NextPtr dd ? ; pointer to next socket in list |
||
36 | .Number dd ? ; socket number (unique within single process) |
||
37 | .PID dd ? ; application process id |
||
38 | .LocalIP dd ? ; local IP address |
||
39 | .LocalPort dw ? ; local port |
||
40 | .RemoteIP dd ? ; remote IP address |
||
41 | .RemotePort dw ? ; remote port |
||
42 | .OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) |
||
43 | .OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) |
||
44 | .rxDataCount dd ? ; rx data count |
||
45 | .TCBState dd ? ; TCB state |
||
46 | .TCBTimer dd ? ; TCB timer (seconds) |
||
47 | .ISS dd ? ; initial send sequence |
||
48 | .IRS dd ? ; initial receive sequence |
||
49 | .SND_UNA dd ? ; sequence number of unack'ed sent packets |
||
50 | .SND_NXT dd ? ; bext send sequence number to use |
||
51 | .SND_WND dd ? ; send window |
||
52 | .RCV_NXT dd ? ; next receive sequence number to use |
||
53 | .RCV_WND dd ? ; receive window |
||
54 | .SEG_LEN dd ? ; segment length |
||
55 | .SEG_WND dd ? ; segment window |
||
56 | .wndsizeTimer dd ? ; window size timer |
||
1019 | diamond | 57 | .lock dd ? ; lock mutex |
922 | mikedld | 58 | .rxData dd ? ; receive data buffer here |
59 | ends |
||
593 | mikedld | 60 | |
922 | mikedld | 61 | ; TCP opening modes |
62 | SOCKET_PASSIVE = 0 |
||
63 | SOCKET_ACTIVE = 1 |
||
261 | hidnplayr | 64 | |
922 | mikedld | 65 | ; socket types |
66 | SOCK_STREAM = 1 |
||
67 | SOCK_DGRAM = 2 |
||
261 | hidnplayr | 68 | |
1154 | clevermous | 69 | ; pointer to bitmap of free ports (1=free, 0=used) |
70 | uglobal |
||
71 | align 4 |
||
72 | network_free_ports dd ? |
||
73 | endg |
||
74 | |||
75 | iglobal |
||
76 | align 4 |
||
77 | network_free_hint dd 1024/8 |
||
78 | endg |
||
79 | |||
922 | mikedld | 80 | ;; Allocate memory for socket data and put new socket into the list |
81 | ; Newly created socket is initialized with calling PID and number and |
||
82 | ; put into beginning of list (which is a fastest way). |
||
83 | ; |
||
84 | ; @return socket structure address in EAX |
||
85 | ;; |
||
907 | mikedld | 86 | proc net_socket_alloc stdcall uses ebx ecx edx edi |
87 | stdcall kernel_alloc, SOCKETBUFFSIZE |
||
88 | DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax |
||
922 | mikedld | 89 | ; check if we can allocate needed amount of memory |
907 | mikedld | 90 | or eax, eax |
91 | jz .exit |
||
92 | |||
922 | mikedld | 93 | ; zero-initialize allocated memory |
907 | mikedld | 94 | push eax |
95 | mov edi, eax |
||
96 | mov ecx, SOCKETBUFFSIZE / 4 |
||
97 | cld |
||
98 | xor eax, eax |
||
99 | rep stosd |
||
100 | pop eax |
||
101 | |||
922 | mikedld | 102 | ; add socket to the list by changing pointers |
907 | mikedld | 103 | mov ebx, net_sockets |
104 | push [ebx + SOCKET.NextPtr] |
||
105 | mov [ebx + SOCKET.NextPtr], eax |
||
106 | mov [eax + SOCKET.PrevPtr], ebx |
||
107 | pop ebx |
||
108 | mov [eax + SOCKET.NextPtr], ebx |
||
109 | or ebx, ebx |
||
110 | jz @f |
||
111 | mov [ebx + SOCKET.PrevPtr], eax |
||
112 | |||
922 | mikedld | 113 | @@: ; set socket owner PID to the one of calling process |
114 | mov ebx, [TASK_BASE] |
||
907 | mikedld | 115 | mov ebx, [ebx + TASKDATA.pid] |
116 | mov [eax + SOCKET.PID], ebx |
||
117 | |||
922 | mikedld | 118 | ; find first free socket number and use it |
119 | ;mov edx, ebx |
||
120 | mov ebx, net_sockets |
||
121 | xor ecx, ecx |
||
122 | .next_socket_number: |
||
123 | inc ecx |
||
124 | .next_socket: |
||
125 | mov ebx, [ebx + SOCKET.NextPtr] |
||
126 | or ebx, ebx |
||
127 | jz .last_socket_number |
||
128 | cmp [ebx + SOCKET.Number], ecx |
||
129 | jne .next_socket |
||
130 | ;cmp [ebx + SOCKET.PID], edx |
||
131 | ;jne .next_socket |
||
132 | mov ebx, net_sockets |
||
133 | jmp .next_socket_number |
||
134 | |||
135 | .last_socket_number: |
||
136 | mov [eax + SOCKET.Number], ecx |
||
137 | |||
907 | mikedld | 138 | .exit: |
139 | ret |
||
140 | endp |
||
141 | |||
922 | mikedld | 142 | ;; Free socket data memory and pop socket off the list |
143 | ; |
||
144 | ; @param sockAddr is a socket structure address |
||
145 | ;; |
||
146 | proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD |
||
147 | mov eax, [sockAddr] |
||
907 | mikedld | 148 | DEBUGF 1, "K : net_socket_free (0x%x)\n", eax |
922 | mikedld | 149 | ; check if we got something similar to socket structure address |
907 | mikedld | 150 | or eax, eax |
151 | jz .error |
||
152 | |||
922 | mikedld | 153 | ; make sure sockAddr is one of the socket addresses in the list |
907 | mikedld | 154 | mov ebx, net_sockets |
922 | mikedld | 155 | ;mov ecx, [TASK_BASE] |
156 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 157 | .next_socket: |
158 | mov ebx, [ebx + SOCKET.NextPtr] |
||
159 | or ebx, ebx |
||
160 | jz .error |
||
161 | cmp ebx, eax |
||
162 | jne .next_socket |
||
163 | ;cmp [ebx + SOCKET.PID], ecx |
||
164 | ;jne .next_socket |
||
165 | |||
922 | mikedld | 166 | ; okay, we found the correct one |
1154 | clevermous | 167 | ; mark local port as unused |
168 | movzx ebx, [eax + SOCKET.LocalPort] |
||
169 | push eax |
||
170 | mov eax, [network_free_ports] |
||
171 | xchg bl, bh |
||
172 | lock bts [eax], ebx |
||
173 | pop eax |
||
922 | mikedld | 174 | ; remove it from the list first, changing pointers |
907 | mikedld | 175 | mov ebx, [eax + SOCKET.NextPtr] |
176 | mov eax, [eax + SOCKET.PrevPtr] |
||
177 | mov [eax + SOCKET.NextPtr], ebx |
||
178 | or ebx, ebx |
||
179 | jz @f |
||
180 | mov [ebx + SOCKET.PrevPtr], eax |
||
181 | |||
922 | mikedld | 182 | @@: ; and finally free the memory structure used |
183 | stdcall kernel_free, [sockAddr] |
||
907 | mikedld | 184 | ret |
185 | |||
186 | .error: |
||
187 | DEBUGF 1, "K : failed\n" |
||
188 | ret |
||
189 | endp |
||
190 | |||
922 | mikedld | 191 | ;; Get socket structure address by its number |
192 | ; Scan through sockets list to find the socket with specified number. |
||
193 | ; This proc uses SOCKET.PID indirectly to check if socket is owned by |
||
194 | ; calling process. |
||
195 | ; |
||
196 | ; @param sockNum is a socket number |
||
197 | ; @return socket structure address or 0 (not found) in EAX |
||
198 | ;; |
||
199 | proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD |
||
200 | mov eax, [sockNum] |
||
201 | ; check if we got something similar to socket number |
||
202 | or eax, eax |
||
203 | jz .error |
||
204 | |||
205 | ; scan through sockets list |
||
907 | mikedld | 206 | mov ebx, net_sockets |
922 | mikedld | 207 | ;mov ecx, [TASK_BASE] |
208 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 209 | .next_socket: |
210 | mov ebx, [ebx + SOCKET.NextPtr] |
||
211 | or ebx, ebx |
||
212 | jz .error |
||
922 | mikedld | 213 | cmp [ebx + SOCKET.Number], eax |
907 | mikedld | 214 | jne .next_socket |
215 | ;cmp [ebx + SOCKET.PID], ecx |
||
216 | ;jne .next_socket |
||
922 | mikedld | 217 | |
218 | ; okay, we found the correct one |
||
219 | mov eax, ebx |
||
907 | mikedld | 220 | ret |
221 | |||
222 | .error: |
||
223 | xor eax, eax |
||
224 | ret |
||
225 | endp |
||
226 | |||
922 | mikedld | 227 | ;; Get socket number by its structure address |
228 | ; Scan through sockets list to find the socket with specified address. |
||
229 | ; This proc uses SOCKET.PID indirectly to check if socket is owned by |
||
230 | ; calling process. |
||
231 | ; |
||
232 | ; @param sockAddr is a socket structure address |
||
233 | ; @return socket number (SOCKET.Number) or 0 (not found) in EAX |
||
234 | ;; |
||
235 | proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD |
||
236 | mov eax, [sockAddr] |
||
237 | ; check if we got something similar to socket structure address |
||
238 | or eax, eax |
||
239 | jz .error |
||
240 | |||
241 | ; scan through sockets list |
||
907 | mikedld | 242 | mov ebx, net_sockets |
922 | mikedld | 243 | ;mov ecx, [TASK_BASE] |
244 | ;mov ecx, [ecx + TASKDATA.pid] |
||
907 | mikedld | 245 | .next_socket: |
246 | mov ebx, [ebx + SOCKET.NextPtr] |
||
247 | or ebx, ebx |
||
248 | jz .error |
||
249 | cmp ebx, eax |
||
250 | jne .next_socket |
||
251 | ;cmp [ebx + SOCKET.PID], ecx |
||
252 | ;jne .next_socket |
||
922 | mikedld | 253 | |
254 | ; okay, we found the correct one |
||
255 | mov eax, [ebx + SOCKET.Number] |
||
907 | mikedld | 256 | ret |
257 | |||
258 | .error: |
||
259 | xor eax, eax |
||
260 | ret |
||
261 | endp |
||
262 | |||
922 | mikedld | 263 | ;; [53.9] Check if local port is used by any socket in the system. |
264 | ; Scan through sockets list, checking SOCKET.LocalPort. |
||
265 | ; Useful when you want a to generate a unique local port number. |
||
266 | ; This proc doesn't guarantee that after calling it and trying to use |
||
267 | ; the port reported being free in calls to socket_open/socket_open_tcp it'll |
||
268 | ; still be free or otherwise it'll still be used if reported being in use. |
||
261 | hidnplayr | 269 | ; |
922 | mikedld | 270 | ; @param BX is a port number |
271 | ; @return 1 (port is free) or 0 (port is in use) in EAX |
||
272 | ;; |
||
907 | mikedld | 273 | proc is_localport_unused stdcall |
1154 | clevermous | 274 | movzx ebx, bx |
275 | mov eax, [network_free_ports] |
||
276 | bt [eax], ebx |
||
277 | setc al |
||
278 | movzx eax, al |
||
907 | mikedld | 279 | ret |
280 | endp |
||
261 | hidnplayr | 281 | |
1154 | clevermous | 282 | ;====================================== |
283 | set_local_port: |
||
284 | ;-------------------------------------- |
||
285 | ;? Set local port in socket structure. |
||
286 | ;-------------------------------------- |
||
287 | ;> eax -> struct SOCKET |
||
288 | ;> bx = local port, or 0 if the kernel must select it itself |
||
289 | ;-------------------------------------- |
||
290 | ;< CF set on error / cleared on success |
||
291 | ;< [eax+SOCKET.LocalPort] filled on success |
||
292 | ;====================================== |
||
293 | ; 0. Prepare: save registers, make eax point to ports table, expand port to ebx. |
||
294 | push eax ecx |
||
295 | mov eax, [network_free_ports] |
||
296 | movzx ebx, bx |
||
297 | ; 1. Test, whether the kernel should choose port itself. If no, proceed to 5. |
||
298 | test ebx, ebx |
||
299 | jnz .given |
||
300 | ; 2. Yes, it should. Set ecx = limit of table, eax = start value |
||
301 | lea ecx, [eax+0x10000/8] |
||
302 | add eax, [network_free_hint] |
||
303 | ; 3. First scan loop: from free hint to end of table. |
||
304 | .scan1: |
||
305 | ; 3a. For each dword, find bit set to 1 |
||
306 | bsf ebx, [eax] |
||
307 | jz .next1 |
||
308 | ; 3b. If such bit has been found, atomically test again and clear it. |
||
309 | lock btr [eax], ebx |
||
310 | ; 3c. If the bit was still set (usual case), we have found and reserved one port. |
||
311 | ; Proceed to 6. |
||
312 | jc .found |
||
313 | ; 3d. Otherwise, someone has reserved it between bsf and btr, so retry search. |
||
314 | jmp .scan1 |
||
315 | .next1: |
||
316 | ; 3e. All bits are cleared, so advance to next dword. |
||
317 | add eax, 4 |
||
318 | ; 3f. Check limit and continue loop. |
||
319 | cmp eax, ecx |
||
320 | jb .scan1 |
||
321 | ; 4. Second scan loop: from port 1024 (start of non-system ports) to free hint. |
||
322 | mov eax, [network_free_ports] |
||
323 | mov ecx, eax |
||
324 | add ecx, [network_free_hint] |
||
325 | add eax, 1024/8 |
||
326 | ; 4a. Test whether there is something to scan. |
||
327 | cmp eax, ecx |
||
328 | jae .fail |
||
329 | ; 4b. Enter the loop, the process is same as for 3. |
||
330 | .scan2: |
||
331 | bsf ebx, [eax] |
||
332 | jz .next2 |
||
333 | lock btr [eax], ebx |
||
334 | jc .found |
||
335 | jmp .scan2 |
||
336 | .next2: |
||
337 | add eax, 4 |
||
338 | cmp eax, ecx |
||
339 | jb .scan2 |
||
340 | ; 4c. None found. Fail. |
||
341 | .fail: |
||
342 | pop ecx eax |
||
343 | stc |
||
344 | ret |
||
345 | ; 5. No, the kernel should reserve selected port. |
||
346 | .given: |
||
347 | ; 5a. Atomically test old value and clear bit. |
||
348 | lock btr [eax], ebx |
||
349 | ; 5b. If the bit was set, reservation is successful. Proceed to 8. |
||
350 | jc .set |
||
351 | ; 5c. Otherwise, fail. |
||
352 | jmp .fail |
||
353 | .found: |
||
354 | ; 6. We have found the bit set to 1, convert the position to port number. |
||
355 | sub eax, [network_free_ports] |
||
356 | lea ebx, [ebx+eax*8] |
||
357 | ; 7. Update free hint. |
||
358 | add eax, 4 |
||
359 | cmp eax, 65536/8 |
||
360 | jb @f |
||
361 | mov eax, 1024/8 |
||
362 | @@: |
||
363 | mov [network_free_hint], eax |
||
364 | .set: |
||
365 | ; 8. Restore eax, set SOCKET.LocalPort and return. |
||
366 | pop ecx eax |
||
367 | xchg bl, bh ; Intel -> network byte order |
||
368 | mov [eax + SOCKET.LocalPort], bx |
||
369 | clc |
||
370 | ret |
||
371 | |||
922 | mikedld | 372 | ;; [53.0] Open DGRAM socket (connectionless, unreliable) |
261 | hidnplayr | 373 | ; |
922 | mikedld | 374 | ; @param BX is local port number |
375 | ; @param CX is remote port number |
||
376 | ; @param EDX is remote IP address |
||
377 | ; @return socket number or -1 (error) in EAX |
||
378 | ;; |
||
907 | mikedld | 379 | proc socket_open stdcall |
380 | call net_socket_alloc |
||
381 | or eax, eax |
||
382 | jz .error |
||
261 | hidnplayr | 383 | |
907 | mikedld | 384 | DEBUGF 1, "K : socket_open (0x%x)\n", eax |
261 | hidnplayr | 385 | |
907 | mikedld | 386 | push eax |
261 | hidnplayr | 387 | |
1154 | clevermous | 388 | call set_local_port |
389 | jc .error.free |
||
907 | mikedld | 390 | xchg ch, cl |
391 | mov [eax + SOCKET.RemotePort], cx |
||
392 | mov ebx, [stack_ip] |
||
393 | mov [eax + SOCKET.LocalIP], ebx |
||
394 | mov [eax + SOCKET.RemoteIP], edx |
||
261 | hidnplayr | 395 | |
907 | mikedld | 396 | ;pop eax ; Get the socket number back, so we can return it |
397 | stdcall net_socket_addr_to_num |
||
398 | ret |
||
261 | hidnplayr | 399 | |
1154 | clevermous | 400 | .error.free: |
401 | stdcall net_socket_free;, eax |
||
402 | |||
907 | mikedld | 403 | .error: |
404 | DEBUGF 1, "K : socket_open (fail)\n" |
||
405 | or eax, -1 |
||
406 | ret |
||
407 | endp |
||
261 | hidnplayr | 408 | |
922 | mikedld | 409 | ;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way) |
261 | hidnplayr | 410 | ; |
922 | mikedld | 411 | ; @param BX is local port number |
412 | ; @param CX is remote port number |
||
413 | ; @param EDX is remote IP address |
||
414 | ; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE) |
||
415 | ; @return socket number or -1 (error) in EAX |
||
416 | ;; |
||
907 | mikedld | 417 | proc socket_open_tcp stdcall |
418 | local sockAddr dd ? |
||
261 | hidnplayr | 419 | |
907 | mikedld | 420 | cmp esi, SOCKET_PASSIVE |
421 | jne .skip_port_check |
||
261 | hidnplayr | 422 | |
907 | mikedld | 423 | push ebx |
424 | mov eax, ebx |
||
425 | xchg al, ah |
||
426 | mov ebx, net_sockets |
||
261 | hidnplayr | 427 | |
907 | mikedld | 428 | .next_socket: |
429 | mov ebx, [ebx + SOCKET.NextPtr] |
||
430 | or ebx, ebx |
||
431 | jz .last_socket |
||
432 | cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
||
433 | jne .next_socket |
||
434 | cmp [ebx + SOCKET.LocalPort], ax |
||
435 | jne .next_socket |
||
261 | hidnplayr | 436 | |
907 | mikedld | 437 | xchg al, ah |
438 | DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx |
||
439 | pop ebx |
||
440 | jmp .error |
||
261 | hidnplayr | 441 | |
907 | mikedld | 442 | .last_socket: |
443 | pop ebx |
||
261 | hidnplayr | 444 | |
907 | mikedld | 445 | .skip_port_check: |
446 | call net_socket_alloc |
||
447 | or eax, eax |
||
448 | jz .error |
||
261 | hidnplayr | 449 | |
907 | mikedld | 450 | DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax |
261 | hidnplayr | 451 | |
907 | mikedld | 452 | mov [sockAddr], eax |
261 | hidnplayr | 453 | |
907 | mikedld | 454 | ; TODO - check this works! |
455 | ;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
||
261 | hidnplayr | 456 | |
1154 | clevermous | 457 | call set_local_port |
458 | jc .error.free |
||
907 | mikedld | 459 | xchg ch, cl |
460 | mov [eax + SOCKET.RemotePort], cx |
||
461 | mov [eax + SOCKET.OrigRemotePort], cx |
||
462 | mov ebx, [stack_ip] |
||
463 | mov [eax + SOCKET.LocalIP], ebx |
||
464 | mov [eax + SOCKET.RemoteIP], edx |
||
465 | mov [eax + SOCKET.OrigRemoteIP], edx |
||
261 | hidnplayr | 466 | |
907 | mikedld | 467 | mov ebx, TCB_LISTEN |
468 | cmp esi, SOCKET_PASSIVE |
||
469 | je @f |
||
470 | mov ebx, TCB_SYN_SENT |
||
471 | @@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
||
261 | hidnplayr | 472 | |
907 | mikedld | 473 | cmp ebx, TCB_LISTEN |
474 | je .exit |
||
261 | hidnplayr | 475 | |
907 | mikedld | 476 | ; Now, if we are in active mode, then we have to send a SYN to the specified remote port |
477 | mov eax, EMPTY_QUEUE |
||
478 | call dequeue |
||
479 | cmp ax, NO_BUFFER |
||
480 | je .exit |
||
261 | hidnplayr | 481 | |
907 | mikedld | 482 | push eax |
261 | hidnplayr | 483 | |
907 | mikedld | 484 | mov bl, TH_SYN |
485 | xor ecx, ecx |
||
486 | stdcall build_tcp_packet, [sockAddr] |
||
261 | hidnplayr | 487 | |
907 | mikedld | 488 | mov eax, NET1OUT_QUEUE |
489 | mov edx, [stack_ip] |
||
490 | mov ecx, [sockAddr] |
||
491 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
492 | jne .not_local |
||
493 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 494 | |
907 | mikedld | 495 | .not_local: |
496 | ; Send it. |
||
497 | pop ebx |
||
498 | call queue |
||
261 | hidnplayr | 499 | |
907 | mikedld | 500 | mov esi, [sockAddr] |
261 | hidnplayr | 501 | |
907 | mikedld | 502 | ; increment SND.NXT in socket |
503 | add esi, SOCKET.SND_NXT |
||
504 | call inc_inet_esi |
||
261 | hidnplayr | 505 | |
907 | mikedld | 506 | .exit: |
922 | mikedld | 507 | ; Get the socket number back, so we can return it |
508 | stdcall net_socket_addr_to_num, [sockAddr] |
||
907 | mikedld | 509 | ret |
261 | hidnplayr | 510 | |
1154 | clevermous | 511 | .error.free: |
512 | stdcall net_socket_free, eax |
||
513 | |||
907 | mikedld | 514 | .error: |
515 | DEBUGF 1, "K : socket_open_tcp (fail)\n" |
||
516 | or eax, -1 |
||
517 | ret |
||
518 | endp |
||
261 | hidnplayr | 519 | |
922 | mikedld | 520 | ;; [53.1] Close DGRAM socket |
261 | hidnplayr | 521 | ; |
922 | mikedld | 522 | ; @param EBX is socket number |
523 | ; @return 0 (closed successfully) or -1 (error) in EAX |
||
524 | ;; |
||
907 | mikedld | 525 | proc socket_close stdcall |
526 | DEBUGF 1, "K : socket_close (0x%x)\n", ebx |
||
527 | stdcall net_socket_num_to_addr, ebx |
||
528 | or eax, eax |
||
529 | jz .error |
||
261 | hidnplayr | 530 | |
907 | mikedld | 531 | stdcall net_socket_free, eax |
261 | hidnplayr | 532 | |
907 | mikedld | 533 | xor eax, eax |
534 | ret |
||
261 | hidnplayr | 535 | |
907 | mikedld | 536 | .error: |
537 | DEBUGF 1, "K : socket_close (fail)\n" |
||
538 | or eax, -1 |
||
539 | ret |
||
540 | endp |
||
261 | hidnplayr | 541 | |
922 | mikedld | 542 | ;; [53.8] Close STREAM socket |
543 | ; Closing TCP sockets takes time, so when you get successful return code |
||
544 | ; from this function doesn't always mean that socket is actually closed. |
||
261 | hidnplayr | 545 | ; |
922 | mikedld | 546 | ; @param EBX is socket number |
547 | ; @return 0 (closed successfully) or -1 (error) in EAX |
||
548 | ;; |
||
907 | mikedld | 549 | proc socket_close_tcp stdcall |
550 | local sockAddr dd ? |
||
922 | mikedld | 551 | |
907 | mikedld | 552 | DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx |
553 | ; first, remove any resend entries |
||
554 | pusha |
||
261 | hidnplayr | 555 | |
907 | mikedld | 556 | mov esi, resendQ |
557 | mov ecx, 0 |
||
261 | hidnplayr | 558 | |
907 | mikedld | 559 | .next_resendq: |
560 | cmp ecx, NUMRESENDENTRIES |
||
561 | je .last_resendq ; None left |
||
562 | cmp [esi + 4], ebx |
||
563 | je @f ; found one |
||
564 | inc ecx |
||
565 | add esi, 8 |
||
566 | jmp .next_resendq |
||
261 | hidnplayr | 567 | |
907 | mikedld | 568 | @@: mov dword[esi + 4], 0 |
569 | inc ecx |
||
570 | add esi, 8 |
||
571 | jmp .next_resendq |
||
261 | hidnplayr | 572 | |
907 | mikedld | 573 | .last_resendq: |
574 | popa |
||
261 | hidnplayr | 575 | |
907 | mikedld | 576 | stdcall net_socket_num_to_addr, ebx |
577 | or eax, eax |
||
578 | jz .error |
||
261 | hidnplayr | 579 | |
907 | mikedld | 580 | mov ebx, eax |
581 | mov [sockAddr], eax |
||
261 | hidnplayr | 582 | |
922 | mikedld | 583 | cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
584 | je .destroy_tcb |
||
585 | cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT |
||
586 | je .destroy_tcb |
||
261 | hidnplayr | 587 | |
907 | mikedld | 588 | ; Now construct the response, and queue for sending by IP |
589 | mov eax, EMPTY_QUEUE |
||
590 | call dequeue |
||
591 | cmp ax, NO_BUFFER |
||
592 | je .error |
||
261 | hidnplayr | 593 | |
907 | mikedld | 594 | push eax |
261 | hidnplayr | 595 | |
1284 | diamond | 596 | mov bl, TH_FIN+TH_ACK |
907 | mikedld | 597 | xor ecx, ecx |
598 | xor esi, esi |
||
599 | stdcall build_tcp_packet, [sockAddr] |
||
261 | hidnplayr | 600 | |
907 | mikedld | 601 | mov ebx, [sockAddr] |
602 | ; increament SND.NXT in socket |
||
603 | lea esi, [ebx + SOCKET.SND_NXT] |
||
604 | call inc_inet_esi |
||
261 | hidnplayr | 605 | |
907 | mikedld | 606 | ; Get the socket state |
607 | mov eax, [ebx + SOCKET.TCBState] |
||
608 | cmp eax, TCB_SYN_RECEIVED |
||
609 | je .fin_wait_1 |
||
610 | cmp eax, TCB_ESTABLISHED |
||
611 | je .fin_wait_1 |
||
261 | hidnplayr | 612 | |
907 | mikedld | 613 | ; assume CLOSE WAIT |
614 | ; Send a fin, then enter last-ack state |
||
615 | mov [ebx + SOCKET.TCBState], TCB_LAST_ACK |
||
616 | jmp .send |
||
261 | hidnplayr | 617 | |
907 | mikedld | 618 | .fin_wait_1: |
619 | ; Send a fin, then enter finwait2 state |
||
620 | mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 |
||
261 | hidnplayr | 621 | |
907 | mikedld | 622 | .send: |
623 | mov eax, NET1OUT_QUEUE |
||
624 | mov edx, [stack_ip] |
||
625 | mov ecx, [sockAddr] |
||
626 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
627 | jne .not_local |
||
628 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 629 | |
907 | mikedld | 630 | .not_local: |
631 | ; Send it. |
||
632 | pop ebx |
||
633 | call queue |
||
634 | jmp .exit |
||
261 | hidnplayr | 635 | |
907 | mikedld | 636 | .destroy_tcb: |
261 | hidnplayr | 637 | |
907 | mikedld | 638 | ; Clear the socket variables |
639 | stdcall net_socket_free, ebx |
||
261 | hidnplayr | 640 | |
907 | mikedld | 641 | .exit: |
642 | xor eax, eax |
||
643 | ret |
||
261 | hidnplayr | 644 | |
907 | mikedld | 645 | .error: |
646 | DEBUGF 1, "K : socket_close_tcp (fail)\n" |
||
647 | or eax, -1 |
||
648 | ret |
||
649 | endp |
||
261 | hidnplayr | 650 | |
922 | mikedld | 651 | ;; [53.2] Poll socket |
261 | hidnplayr | 652 | ; |
922 | mikedld | 653 | ; @param EBX is socket number |
654 | ; @return count or bytes in rx buffer or 0 (error) in EAX |
||
655 | ;; |
||
907 | mikedld | 656 | proc socket_poll stdcall |
657 | ; DEBUGF 1, "socket_poll(0x%x)\n", ebx |
||
658 | stdcall net_socket_num_to_addr, ebx |
||
659 | or eax, eax |
||
660 | jz .error |
||
261 | hidnplayr | 661 | |
907 | mikedld | 662 | mov eax, [eax + SOCKET.rxDataCount] |
663 | ret |
||
261 | hidnplayr | 664 | |
907 | mikedld | 665 | .error: |
666 | xor eax, eax |
||
667 | ret |
||
668 | endp |
||
261 | hidnplayr | 669 | |
922 | mikedld | 670 | ;; [53.6] Get socket TCB state |
261 | hidnplayr | 671 | ; |
922 | mikedld | 672 | ; @param EBX is socket number |
673 | ; @return socket TCB state or 0 (error) in EAX |
||
674 | ;; |
||
907 | mikedld | 675 | proc socket_status stdcall |
676 | ;; DEBUGF 1, "socket_status(0x%x)\n", ebx |
||
677 | stdcall net_socket_num_to_addr, ebx |
||
678 | or eax, eax |
||
679 | jz .error |
||
261 | hidnplayr | 680 | |
907 | mikedld | 681 | mov eax, [eax + SOCKET.TCBState] |
682 | ret |
||
261 | hidnplayr | 683 | |
907 | mikedld | 684 | .error: |
685 | xor eax, eax |
||
686 | ret |
||
687 | endp |
||
261 | hidnplayr | 688 | |
922 | mikedld | 689 | ;; [53.3] Get one byte from rx buffer |
690 | ; This function can return 0 in two cases: if there's one byte read and |
||
691 | ; non left, and if an error occured. Behavior should be changed and function |
||
692 | ; shouldn't be used for now. Consider using [53.11] instead. |
||
907 | mikedld | 693 | ; |
922 | mikedld | 694 | ; @param EBX is socket number |
695 | ; @return number of bytes left in rx buffer or 0 (error) in EAX |
||
696 | ; @return byte read in BL |
||
697 | ;; |
||
907 | mikedld | 698 | proc socket_read stdcall |
699 | ; DEBUGF 1, "socket_read(0x%x)\n", ebx |
||
700 | stdcall net_socket_num_to_addr, ebx |
||
701 | or eax, eax |
||
702 | jz .error |
||
261 | hidnplayr | 703 | |
1019 | diamond | 704 | lea ebx, [eax + SOCKET.lock] |
705 | call wait_mutex |
||
706 | |||
907 | mikedld | 707 | mov ebx, eax |
708 | mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
||
709 | test eax, eax |
||
1019 | diamond | 710 | jz .error_release |
261 | hidnplayr | 711 | |
907 | mikedld | 712 | dec eax |
915 | mikedld | 713 | mov esi, ebx ; esi is address of socket |
907 | mikedld | 714 | mov [ebx + SOCKET.rxDataCount], eax ; store new count |
1019 | diamond | 715 | movzx eax, byte[ebx + SOCKET.rxData] ; get the byte |
261 | hidnplayr | 716 | |
915 | mikedld | 717 | mov ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1 |
718 | lea edi, [esi + SOCKET.rxData] |
||
907 | mikedld | 719 | lea esi, [edi + 1] |
720 | cld |
||
915 | mikedld | 721 | push ecx |
722 | shr ecx, 2 |
||
907 | mikedld | 723 | rep movsd |
915 | mikedld | 724 | pop ecx |
725 | and ecx, 3 |
||
726 | rep movsb |
||
261 | hidnplayr | 727 | |
1019 | diamond | 728 | mov [ebx + SOCKET.lock], 0 |
729 | mov ebx, eax |
||
730 | |||
907 | mikedld | 731 | ret |
261 | hidnplayr | 732 | |
1019 | diamond | 733 | .error_release: |
734 | mov [ebx + SOCKET.lock], 0 |
||
907 | mikedld | 735 | .error: |
736 | xor ebx, ebx |
||
737 | ret |
||
738 | endp |
||
261 | hidnplayr | 739 | |
922 | mikedld | 740 | ;; [53.11] Get specified number of bytes from rx buffer |
741 | ; Number of bytes in rx buffer can be less than requested size. In this case, |
||
742 | ; only available number of bytes is read. |
||
743 | ; This function can return 0 in two cases: if there's no data to read, and if |
||
744 | ; an error occured. Behavior should be changed. |
||
323 | hidnplayr | 745 | ; |
922 | mikedld | 746 | ; @param EBX is socket number |
747 | ; @param ECX is pointer to application buffer |
||
748 | ; @param EDX is application buffer size (number of bytes to read) |
||
749 | ; @return number of bytes read or 0 (error) in EAX |
||
750 | ;; |
||
907 | mikedld | 751 | proc socket_read_packet stdcall |
752 | ; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx |
||
753 | stdcall net_socket_num_to_addr, ebx ; get real socket address |
||
754 | or eax, eax |
||
755 | jz .error |
||
261 | hidnplayr | 756 | |
1019 | diamond | 757 | lea ebx, [eax + SOCKET.lock] |
758 | call wait_mutex |
||
759 | |||
907 | mikedld | 760 | mov ebx, eax |
761 | mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
||
762 | test eax, eax ; if count of bytes is zero.. |
||
763 | jz .exit ; exit function (eax will be zero) |
||
323 | hidnplayr | 764 | |
907 | mikedld | 765 | test edx, edx ; if buffer size is zero, copy all data |
766 | jz .copy_all_bytes |
||
767 | cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data |
||
768 | jge .copy_all_bytes |
||
323 | hidnplayr | 769 | |
907 | mikedld | 770 | sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy) |
771 | mov [ebx + SOCKET.rxDataCount], eax ; |
||
772 | push eax |
||
773 | mov eax, edx ; number of bytes we want to copy must be in eax |
||
774 | call .start_copy ; copy to the application |
||
323 | hidnplayr | 775 | |
907 | mikedld | 776 | mov esi, ebx ; now we're going to copy the remaining bytes to the beginning |
915 | mikedld | 777 | add esi, SOCKET.rxData ; we dont need to copy the header |
907 | mikedld | 778 | mov edi, esi ; edi is where we're going to copy to |
779 | add esi, edx ; esi is from where we copy |
||
780 | pop ecx ; count of bytes we have left |
||
781 | push ecx ; push it again so we can re-use it later |
||
782 | shr ecx, 2 ; divide eax by 4 |
||
783 | cld |
||
784 | rep movsd ; copy all full dwords |
||
785 | pop ecx |
||
786 | and ecx, 3 |
||
787 | rep movsb ; copy remaining bytes |
||
323 | hidnplayr | 788 | |
907 | mikedld | 789 | .exit: |
1019 | diamond | 790 | mov [ebx + SOCKET.lock], 0 |
907 | mikedld | 791 | ret ; at last, exit |
323 | hidnplayr | 792 | |
907 | mikedld | 793 | .error: |
794 | xor eax, eax |
||
795 | ret |
||
323 | hidnplayr | 796 | |
907 | mikedld | 797 | .copy_all_bytes: |
798 | xor esi, esi |
||
799 | mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) |
||
800 | call .start_copy |
||
1019 | diamond | 801 | mov [ebx + SOCKET.lock], 0 |
907 | mikedld | 802 | ret |
323 | hidnplayr | 803 | |
907 | mikedld | 804 | .start_copy: |
805 | mov edi, ecx |
||
806 | mov esi, ebx |
||
915 | mikedld | 807 | add esi, SOCKET.rxData ; we dont need to copy the header |
907 | mikedld | 808 | mov ecx, eax ; eax is count of bytes |
809 | push ecx |
||
810 | shr ecx, 2 ; divide eax by 4 |
||
811 | cld ; copy all full dwords |
||
812 | rep movsd |
||
813 | pop ecx |
||
814 | and ecx, 3 |
||
815 | rep movsb ; copy the rest bytes |
||
816 | retn ; exit, or go back to shift remaining bytes if any |
||
817 | endp |
||
323 | hidnplayr | 818 | |
922 | mikedld | 819 | ;; [53.4] Send data through DGRAM socket |
261 | hidnplayr | 820 | ; |
922 | mikedld | 821 | ; @param EBX is socket number |
822 | ; @param ECX is application data size (number of bytes to send) |
||
823 | ; @param EDX is pointer to application data buffer |
||
824 | ; @return 0 (sent successfully) or -1 (error) in EAX |
||
825 | ;; |
||
907 | mikedld | 826 | proc socket_write stdcall |
827 | ; DEBUGF 1, "socket_write(0x%x)\n", ebx |
||
828 | stdcall net_socket_num_to_addr, ebx ; get real socket address |
||
829 | or eax, eax |
||
830 | jz .error |
||
261 | hidnplayr | 831 | |
907 | mikedld | 832 | mov ebx, eax |
261 | hidnplayr | 833 | |
907 | mikedld | 834 | mov eax, EMPTY_QUEUE |
835 | call dequeue |
||
836 | cmp ax, NO_BUFFER |
||
837 | je .error |
||
261 | hidnplayr | 838 | |
907 | mikedld | 839 | ; Save the queue entry number |
840 | push eax |
||
261 | hidnplayr | 841 | |
907 | mikedld | 842 | ; save the pointers to the data buffer & size |
843 | push edx |
||
844 | push ecx |
||
261 | hidnplayr | 845 | |
907 | mikedld | 846 | ; convert buffer pointer eax to the absolute address |
847 | mov ecx, IPBUFFSIZE |
||
848 | mul ecx |
||
849 | add eax, IPbuffs |
||
261 | hidnplayr | 850 | |
907 | mikedld | 851 | mov edx, eax |
261 | hidnplayr | 852 | |
907 | mikedld | 853 | ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr |
261 | hidnplayr | 854 | |
907 | mikedld | 855 | ; Fill in the IP header (some data is in the socket descriptor) |
856 | mov eax, [ebx + SOCKET.LocalIP] |
||
857 | mov [edx + IP_PACKET.SourceAddress], eax |
||
858 | mov eax, [ebx + SOCKET.RemoteIP] |
||
859 | mov [edx + IP_PACKET.DestinationAddress], eax |
||
261 | hidnplayr | 860 | |
907 | mikedld | 861 | mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
862 | mov [edx + IP_PACKET.TypeOfService], 0 |
||
261 | hidnplayr | 863 | |
907 | mikedld | 864 | pop eax ; Get the UDP data length |
865 | push eax |
||
261 | hidnplayr | 866 | |
907 | mikedld | 867 | add eax, 20 + 8 ; add IP header and UDP header lengths |
868 | xchg al, ah |
||
869 | mov [edx + IP_PACKET.TotalLength], ax |
||
870 | xor eax, eax |
||
871 | mov [edx + IP_PACKET.Identification], ax |
||
872 | mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
||
873 | mov [edx + IP_PACKET.TimeToLive], 0x20 |
||
874 | mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP |
||
261 | hidnplayr | 875 | |
907 | mikedld | 876 | ; Checksum left unfilled |
877 | mov [edx + IP_PACKET.HeaderChecksum], ax |
||
261 | hidnplayr | 878 | |
907 | mikedld | 879 | ; Fill in the UDP header (some data is in the socket descriptor) |
880 | mov ax, [ebx + SOCKET.LocalPort] |
||
881 | mov [edx + 20 + UDP_PACKET.SourcePort], ax |
||
261 | hidnplayr | 882 | |
907 | mikedld | 883 | mov ax, [ebx + SOCKET.RemotePort] |
884 | mov [edx + 20 + UDP_PACKET.DestinationPort], ax |
||
261 | hidnplayr | 885 | |
907 | mikedld | 886 | pop eax |
887 | push eax |
||
261 | hidnplayr | 888 | |
907 | mikedld | 889 | add eax, 8 |
890 | xchg al, ah |
||
891 | mov [edx + 20 + UDP_PACKET.Length], ax |
||
261 | hidnplayr | 892 | |
907 | mikedld | 893 | ; Checksum left unfilled |
894 | xor eax, eax |
||
895 | mov [edx + 20 + UDP_PACKET.Checksum], ax |
||
261 | hidnplayr | 896 | |
907 | mikedld | 897 | pop ecx ; count of bytes to send |
898 | mov ebx, ecx ; need the length later |
||
899 | pop eax ; get callers ptr to data to send |
||
261 | hidnplayr | 900 | |
907 | mikedld | 901 | ; Get the address of the callers data |
902 | mov edi, [TASK_BASE] |
||
903 | add edi, TASKDATA.mem_start |
||
904 | add eax, [edi] |
||
905 | mov esi, eax |
||
261 | hidnplayr | 906 | |
907 | mikedld | 907 | mov edi, edx |
908 | add edi, 28 |
||
909 | cld |
||
910 | rep movsb ; copy the data across |
||
261 | hidnplayr | 911 | |
907 | mikedld | 912 | ; we have edx as IPbuffer ptr. |
913 | ; Fill in the UDP checksum |
||
914 | ; First, fill in pseudoheader |
||
915 | mov eax, [edx + IP_PACKET.SourceAddress] |
||
916 | mov [pseudoHeader], eax |
||
917 | mov eax, [edx + IP_PACKET.DestinationAddress] |
||
918 | mov [pseudoHeader + 4], eax |
||
919 | mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol |
||
920 | add ebx, 8 |
||
921 | mov eax, ebx |
||
922 | xchg al, ah |
||
923 | mov [pseudoHeader + 10], ax |
||
261 | hidnplayr | 924 | |
907 | mikedld | 925 | mov eax, pseudoHeader |
926 | mov [checkAdd1], eax |
||
927 | mov [checkSize1], word 12 |
||
928 | mov eax, edx |
||
929 | add eax, 20 |
||
930 | mov [checkAdd2], eax |
||
931 | mov eax, ebx |
||
932 | mov [checkSize2], ax ; was eax!! mjh 8/7/02 |
||
261 | hidnplayr | 933 | |
907 | mikedld | 934 | call checksum |
261 | hidnplayr | 935 | |
907 | mikedld | 936 | ; store it in the UDP checksum ( in the correct order! ) |
937 | mov ax, [checkResult] |
||
261 | hidnplayr | 938 | |
907 | mikedld | 939 | ; If the UDP checksum computes to 0, we must make it 0xffff |
940 | ; (0 is reserved for 'not used') |
||
941 | test ax, ax |
||
942 | jnz @f |
||
943 | mov ax, 0xffff |
||
261 | hidnplayr | 944 | |
907 | mikedld | 945 | @@: xchg al, ah |
946 | mov [edx + 20 + UDP_PACKET.Checksum], ax |
||
261 | hidnplayr | 947 | |
907 | mikedld | 948 | ; Fill in the IP header checksum |
949 | GET_IHL ecx,edx ; get IP-Header length |
||
950 | stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size |
||
951 | xchg al, ah |
||
952 | mov [edx + IP_PACKET.HeaderChecksum], ax |
||
261 | hidnplayr | 953 | |
907 | mikedld | 954 | ; Check destination IP address. |
955 | ; If it is the local host IP, route it back to IP_RX |
||
261 | hidnplayr | 956 | |
907 | mikedld | 957 | pop ebx |
261 | hidnplayr | 958 | |
907 | mikedld | 959 | mov eax, NET1OUT_QUEUE |
960 | mov ecx, [edx + SOCKET.RemoteIP] |
||
961 | mov edx, [stack_ip] |
||
962 | cmp edx, ecx |
||
963 | jne .not_local |
||
964 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 965 | |
907 | mikedld | 966 | .not_local: |
967 | ; Send it. |
||
968 | call queue |
||
261 | hidnplayr | 969 | |
907 | mikedld | 970 | xor eax, eax |
971 | ret |
||
261 | hidnplayr | 972 | |
907 | mikedld | 973 | .error: |
974 | or eax, -1 |
||
975 | ret |
||
976 | endp |
||
261 | hidnplayr | 977 | |
922 | mikedld | 978 | ;; [53.7] Send data through STREAM socket |
261 | hidnplayr | 979 | ; |
922 | mikedld | 980 | ; @param EBX is socket number |
981 | ; @param ECX is application data size (number of bytes to send) |
||
982 | ; @param EDX is pointer to application data buffer |
||
983 | ; @return 0 (sent successfully) or -1 (error) in EAX |
||
984 | ;; |
||
907 | mikedld | 985 | proc socket_write_tcp stdcall |
986 | local sockAddr dd ? |
||
261 | hidnplayr | 987 | |
907 | mikedld | 988 | ; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx |
989 | stdcall net_socket_num_to_addr, ebx |
||
990 | or eax, eax |
||
991 | jz .error |
||
261 | hidnplayr | 992 | |
907 | mikedld | 993 | mov ebx, eax |
994 | mov [sockAddr], ebx |
||
261 | hidnplayr | 995 | |
907 | mikedld | 996 | ; If the sockets window timer is nonzero, do not queue packet |
997 | cmp [ebx + SOCKET.wndsizeTimer], 0 |
||
998 | jne .error |
||
261 | hidnplayr | 999 | |
907 | mikedld | 1000 | mov eax, EMPTY_QUEUE |
1001 | call dequeue |
||
1002 | cmp ax, NO_BUFFER |
||
1003 | je .error |
||
261 | hidnplayr | 1004 | |
907 | mikedld | 1005 | push eax |
261 | hidnplayr | 1006 | |
907 | mikedld | 1007 | ; Get the address of the callers data |
1008 | mov edi, [TASK_BASE] |
||
1009 | add edi, TASKDATA.mem_start |
||
1010 | add edx, [edi] |
||
1011 | mov esi, edx |
||
261 | hidnplayr | 1012 | |
907 | mikedld | 1013 | pop eax |
1014 | push eax |
||
261 | hidnplayr | 1015 | |
907 | mikedld | 1016 | push ecx |
1017 | mov bl, TH_ACK |
||
1018 | stdcall build_tcp_packet, [sockAddr] |
||
1019 | pop ecx |
||
261 | hidnplayr | 1020 | |
907 | mikedld | 1021 | ; Check destination IP address. |
1022 | ; If it is the local host IP, route it back to IP_RX |
||
261 | hidnplayr | 1023 | |
907 | mikedld | 1024 | pop ebx |
1025 | push ecx |
||
261 | hidnplayr | 1026 | |
907 | mikedld | 1027 | mov eax, NET1OUT_QUEUE |
1028 | mov edx, [stack_ip] |
||
1029 | mov ecx, [sockAddr] |
||
1030 | cmp edx, [ecx + SOCKET.RemoteIP] |
||
1031 | jne .not_local |
||
1032 | mov eax, IPIN_QUEUE |
||
261 | hidnplayr | 1033 | |
907 | mikedld | 1034 | .not_local: |
1035 | pop ecx |
||
1036 | push ebx ; save ipbuffer number |
||
261 | hidnplayr | 1037 | |
907 | mikedld | 1038 | call queue |
261 | hidnplayr | 1039 | |
907 | mikedld | 1040 | mov esi, [sockAddr] |
261 | hidnplayr | 1041 | |
907 | mikedld | 1042 | ; increament SND.NXT in socket |
1043 | ; Amount to increment by is in ecx |
||
1044 | add esi, SOCKET.SND_NXT |
||
1045 | call add_inet_esi |
||
261 | hidnplayr | 1046 | |
907 | mikedld | 1047 | pop ebx |
261 | hidnplayr | 1048 | |
907 | mikedld | 1049 | ; Copy the IP buffer to a resend queue |
1050 | ; If there isn't one, dont worry about it for now |
||
1051 | mov esi, resendQ |
||
1052 | mov ecx, 0 |
||
261 | hidnplayr | 1053 | |
907 | mikedld | 1054 | .next_resendq: |
1055 | cmp ecx, NUMRESENDENTRIES |
||
1056 | je .exit ; None found |
||
1057 | cmp dword[esi + 4], 0 |
||
1058 | je @f ; found one |
||
1059 | inc ecx |
||
1060 | add esi, 8 |
||
1061 | jmp .next_resendq |
||
261 | hidnplayr | 1062 | |
907 | mikedld | 1063 | @@: push ebx |
261 | hidnplayr | 1064 | |
907 | mikedld | 1065 | ; OK, we have a buffer descriptor ptr in esi. |
1066 | ; resend entry # in ecx |
||
1067 | ; Populate it |
||
1068 | ; socket # |
||
1069 | ; retries count |
||
1070 | ; retry time |
||
1071 | ; fill IP buffer associated with this descriptor |
||
261 | hidnplayr | 1072 | |
907 | mikedld | 1073 | stdcall net_socket_addr_to_num, [sockAddr] |
1074 | mov [esi + 4], eax |
||
1075 | mov byte[esi + 1], TCP_RETRIES |
||
1076 | mov word[esi + 2], TCP_TIMEOUT |
||
261 | hidnplayr | 1077 | |
907 | mikedld | 1078 | inc ecx |
1079 | ; Now get buffer location, and copy buffer across. argh! more copying,, |
||
1080 | mov edi, resendBuffer - IPBUFFSIZE |
||
261 | hidnplayr | 1081 | |
907 | mikedld | 1082 | @@: add edi, IPBUFFSIZE |
1083 | loop @b |
||
261 | hidnplayr | 1084 | |
907 | mikedld | 1085 | ; we have dest buffer location in edi |
1086 | pop eax |
||
1087 | ; convert source buffer pointer eax to the absolute address |
||
1088 | mov ecx, IPBUFFSIZE |
||
1089 | mul ecx |
||
1090 | add eax, IPbuffs |
||
1091 | mov esi, eax |
||
261 | hidnplayr | 1092 | |
907 | mikedld | 1093 | ; do copy |
1094 | mov ecx, IPBUFFSIZE |
||
1095 | cld |
||
1096 | rep movsb |
||
261 | hidnplayr | 1097 | |
907 | mikedld | 1098 | .exit: |
1099 | xor eax, eax |
||
1100 | ret |
||
261 | hidnplayr | 1101 | |
907 | mikedld | 1102 | .error: |
1103 | or eax, -1 |
||
1104 | ret |
||
1105 | endp>> |