Subversion Repositories Kolibri OS

Rev

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