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