Rev 1830 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1830 | Rev 1831 | ||
---|---|---|---|
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
2 | ;; ;; |
3 | ;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
3 | ;; Copyright (C) KolibriOS team 2004-2011. 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 | ;; Part of the tcp/ip network stack for KolibriOS ;; |
6 | ;; Part of the tcp/ip network stack for KolibriOS ;; |
7 | ;; ;; |
7 | ;; ;; |
8 | ;; Written by hidnplayr@kolibrios.org ;; |
8 | ;; Written by hidnplayr@kolibrios.org ;; |
9 | ;; ;; |
9 | ;; ;; |
10 | ;; Based on the code of 4.4BSD ;; |
10 | ;; Based on the code of 4.4BSD ;; |
11 | ;; ;; |
11 | ;; ;; |
12 | ;; GNU GENERAL PUBLIC LICENSE ;; |
12 | ;; GNU GENERAL PUBLIC LICENSE ;; |
13 | ;; Version 2, June 1991 ;; |
13 | ;; Version 2, June 1991 ;; |
14 | ;; ;; |
14 | ;; ;; |
15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
16 | 16 | ||
17 | $Revision: 1830 $ |
17 | $Revision: 1831 $ |
18 | 18 | ||
19 | macro TCP_checksum IP1, IP2 { |
19 | macro TCP_checksum IP1, IP2 { |
20 | 20 | ||
21 | ;------------- |
21 | ;------------- |
22 | ; Pseudoheader |
22 | ; Pseudoheader |
23 | 23 | ||
24 | ; protocol type |
24 | ; protocol type |
25 | mov edx, IP_PROTO_TCP |
25 | mov edx, IP_PROTO_TCP |
26 | 26 | ||
27 | ; source address |
27 | ; source address |
28 | add dl, byte [IP1+1] |
28 | add dl, byte [IP1+1] |
29 | adc dh, byte [IP1+0] |
29 | adc dh, byte [IP1+0] |
30 | adc dl, byte [IP1+3] |
30 | adc dl, byte [IP1+3] |
31 | adc dh, byte [IP1+2] |
31 | adc dh, byte [IP1+2] |
32 | 32 | ||
33 | ; destination address |
33 | ; destination address |
34 | adc dl, byte [IP2+1] |
34 | adc dl, byte [IP2+1] |
35 | adc dh, byte [IP2+0] |
35 | adc dh, byte [IP2+0] |
36 | adc dl, byte [IP2+3] |
36 | adc dl, byte [IP2+3] |
37 | adc dh, byte [IP2+2] |
37 | adc dh, byte [IP2+2] |
38 | 38 | ||
39 | ; size |
39 | ; size |
40 | adc dl, cl |
40 | adc dl, cl |
41 | adc dh, ch |
41 | adc dh, ch |
42 | 42 | ||
43 | ;--------------------- |
43 | ;--------------------- |
44 | ; Real header and data |
44 | ; Real header and data |
45 | 45 | ||
46 | push esi |
46 | push esi |
47 | call checksum_1 |
47 | call checksum_1 |
48 | call checksum_2 |
48 | call checksum_2 |
49 | pop esi |
49 | pop esi |
50 | 50 | ||
51 | } ; returns in dx only |
51 | } ; returns in dx only |
52 | 52 | ||
53 | 53 | ||
54 | 54 | ||
55 | 55 | ||
56 | macro TCP_sendseqinit ptr { |
56 | macro TCP_sendseqinit ptr { |
57 | 57 | ||
58 | push edi ;;;; i dont like this static use of edi |
58 | push edi ;;;; i dont like this static use of edi |
59 | mov edi, [ptr + TCP_SOCKET.ISS] |
59 | mov edi, [ptr + TCP_SOCKET.ISS] |
60 | mov [ptr + TCP_SOCKET.SND_UP], edi |
60 | mov [ptr + TCP_SOCKET.SND_UP], edi |
61 | mov [ptr + TCP_SOCKET.SND_MAX], edi |
61 | mov [ptr + TCP_SOCKET.SND_MAX], edi |
62 | mov [ptr + TCP_SOCKET.SND_NXT], edi |
62 | mov [ptr + TCP_SOCKET.SND_NXT], edi |
63 | mov [ptr + TCP_SOCKET.SND_UNA], edi |
63 | mov [ptr + TCP_SOCKET.SND_UNA], edi |
64 | pop edi |
64 | pop edi |
65 | 65 | ||
66 | } |
66 | } |
67 | 67 | ||
68 | 68 | ||
69 | 69 | ||
70 | macro TCP_rcvseqinit ptr { |
70 | macro TCP_rcvseqinit ptr { |
71 | 71 | ||
72 | push edi |
72 | push edi |
73 | mov edi, [ptr + TCP_SOCKET.IRS] |
73 | mov edi, [ptr + TCP_SOCKET.IRS] |
74 | inc edi |
74 | inc edi |
75 | mov [ptr + TCP_SOCKET.RCV_NXT], edi |
75 | mov [ptr + TCP_SOCKET.RCV_NXT], edi |
76 | mov [ptr + TCP_SOCKET.RCV_ADV], edi |
76 | mov [ptr + TCP_SOCKET.RCV_ADV], edi |
77 | pop edi |
77 | pop edi |
78 | 78 | ||
79 | } |
79 | } |
80 | 80 | ||
81 | 81 | ||
82 | 82 | ||
83 | 83 | ||
84 | 84 | ||
85 | 85 | ||
86 | 86 | ||
87 | 87 | ||
88 | 88 | ||
89 | 89 | ||
90 | ;--------------------------- |
90 | ;--------------------------- |
91 | ; |
91 | ; |
92 | ; TCP_pull_out_of_band |
92 | ; TCP_pull_out_of_band |
93 | ; |
93 | ; |
94 | ; IN: eax = |
94 | ; IN: eax = |
95 | ; ebx = socket ptr |
95 | ; ebx = socket ptr |
96 | ; edx = tcp packet ptr |
96 | ; edx = tcp packet ptr |
97 | ; |
97 | ; |
98 | ; OUT: / |
98 | ; OUT: / |
99 | ; |
99 | ; |
100 | ;--------------------------- |
100 | ;--------------------------- |
101 | 101 | ||
102 | align 4 |
102 | align 4 |
103 | TCP_pull_out_of_band: |
103 | TCP_pull_out_of_band: |
104 | 104 | ||
105 | DEBUGF 1,"TCP_pull_out_of_band\n" |
105 | DEBUGF 1,"TCP_pull_out_of_band\n" |
106 | 106 | ||
107 | ;;;; 1282-1305 |
107 | ;;;; 1282-1305 |
108 | 108 | ||
109 | ret |
109 | ret |
110 | 110 | ||
111 | 111 | ||
112 | 112 | ||
113 | 113 | ||
114 | 114 | ||
115 | 115 | ||
116 | 116 | ||
117 | 117 | ||
118 | ;------------------------- |
118 | ;------------------------- |
119 | ; |
119 | ; |
120 | ; TCP_drop |
120 | ; TCP_drop |
121 | ; |
121 | ; |
122 | ; IN: eax = socket ptr |
122 | ; IN: eax = socket ptr |
123 | ; ebx = error number |
123 | ; ebx = error number |
124 | ; |
124 | ; |
125 | ; OUT: eax = socket ptr |
125 | ; OUT: eax = socket ptr |
126 | ; |
126 | ; |
127 | ;------------------------- |
127 | ;------------------------- |
128 | align 4 |
128 | align 4 |
129 | TCP_drop: |
129 | TCP_drop: |
130 | 130 | ||
131 | DEBUGF 1,"TCP_drop\n" |
131 | DEBUGF 1,"TCP_drop\n" |
132 | 132 | ||
133 | cmp [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED |
133 | cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED |
134 | jl .no_syn_received |
134 | jl .no_syn_received |
135 | 135 | ||
136 | mov [eax + TCP_SOCKET.t_state], TCB_CLOSED |
136 | mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED |
137 | 137 | ||
138 | call TCP_output |
138 | call TCP_output |
139 | 139 | ||
140 | ;;; TODO: update stats |
140 | ;;; TODO: update stats |
141 | 141 | ||
142 | jmp TCP_close |
142 | jmp TCP_close |
143 | 143 | ||
144 | .no_syn_received: |
144 | .no_syn_received: |
145 | 145 | ||
146 | ;;; TODO: update stats |
146 | ;;; TODO: update stats |
147 | 147 | ||
148 | ;;; TODO: check if error code is "Connection timed out' and handle accordingly |
148 | ;;; TODO: check if error code is "Connection timed out' and handle accordingly |
149 | 149 | ||
150 | mov [eax + SOCKET.errorcode], ebx |
150 | mov [eax + SOCKET.errorcode], ebx |
151 | 151 | ||
152 | 152 | ||
153 | 153 | ||
154 | 154 | ||
155 | 155 | ||
156 | 156 | ||
157 | 157 | ||
158 | 158 | ||
159 | ;------------------------- |
159 | ;------------------------- |
160 | ; |
160 | ; |
161 | ; TCP_close |
161 | ; TCP_close |
162 | ; |
162 | ; |
163 | ; IN: eax = socket ptr |
163 | ; IN: eax = socket ptr |
164 | ; OUT: eax = socket ptr |
164 | ; OUT: eax = socket ptr |
165 | ; |
165 | ; |
166 | ;------------------------- |
166 | ;------------------------- |
167 | align 4 |
167 | align 4 |
168 | TCP_close: |
168 | TCP_close: |
169 | 169 | ||
170 | DEBUGF 1,"TCP_close\n" |
170 | DEBUGF 1,"TCP_close\n" |
171 | 171 | ||
172 | ;;; TODO: update RTT and mean deviation |
172 | ;;; TODO: update RTT and mean deviation |
173 | ;;; TODO: update slow start threshold |
173 | ;;; TODO: update slow start threshold |
174 | ;;; TODO: release connection resources |
174 | ;;; TODO: release connection resources |
175 | 175 | ||
176 | ; Now, mark the socket as being disconnected |
176 | ; Now, mark the socket as being disconnected |
177 | 177 | ||
178 | mov [eax + SOCKET.state], 0 ;;; FIXME |
178 | mov [eax + SOCKET.state], 0 ;;; FIXME |
179 | 179 | ||
180 | ret |
180 | ret |
181 | 181 | ||
182 | 182 | ||
183 | 183 | ||
184 | 184 | ||
185 | 185 | ||
186 | 186 | ||
187 | 187 | ||
188 | 188 | ||
189 | 189 | ||
190 | 190 | ||
191 | ;------------------------- |
191 | ;------------------------- |
192 | ; |
192 | ; |
193 | ; TCP_outflags |
193 | ; TCP_outflags |
194 | ; |
194 | ; |
195 | ; IN: eax = socket ptr |
195 | ; IN: eax = socket ptr |
196 | ; |
196 | ; |
197 | ; OUT: edx = flags |
197 | ; OUT: edx = flags |
198 | ; |
198 | ; |
199 | ;------------------------- |
199 | ;------------------------- |
200 | align 4 |
200 | align 4 |
201 | TCP_outflags: |
201 | TCP_outflags: |
202 | 202 | ||
203 | mov edx, [eax + TCP_SOCKET.t_state] |
203 | mov edx, [eax + TCP_SOCKET.t_state] |
204 | movzx edx, byte [edx + .flaglist] |
204 | movzx edx, byte [edx + .flaglist] |
205 | 205 | ||
206 | DEBUGF 1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl |
206 | DEBUGF 1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl |
207 | 207 | ||
208 | ret |
208 | ret |
209 | 209 | ||
210 | .flaglist: |
210 | .flaglist: |
211 | 211 | ||
212 | db TH_RST + TH_ACK ; TCB_CLOSED |
212 | db TH_RST + TH_ACK ; TCPS_CLOSED |
213 | db 0 ; TCB_LISTEN |
213 | db 0 ; TCPS_LISTEN |
214 | db TH_SYN ; TCB_SYN_SENT |
214 | db TH_SYN ; TCPS_SYN_SENT |
215 | db TH_SYN + TH_ACK ; TCB_SYN_RECEIVED |
215 | db TH_SYN + TH_ACK ; TCPS_SYN_RECEIVED |
216 | db TH_ACK ; TCB_ESTABLISHED |
216 | db TH_ACK ; TCPS_ESTABLISHED |
217 | db TH_ACK ; TCB_CLOSE_WAIT |
217 | db TH_ACK ; TCPS_CLOSE_WAIT |
218 | db TH_SYN + TH_ACK ; TCB_FIN_WAIT_1 |
218 | db TH_SYN + TH_ACK ; TCPS_FIN_WAIT_1 |
219 | db TH_SYN + TH_ACK ; TCB_CLOSING |
219 | db TH_SYN + TH_ACK ; TCPS_CLOSING |
220 | db TH_SYN + TH_ACK ; TCB_LAST_ACK |
220 | db TH_SYN + TH_ACK ; TCPS_LAST_ACK |
221 | db TH_ACK ; TCB_FIN_WAIT_2 |
221 | db TH_ACK ; TCPS_FIN_WAIT_2 |
222 | db TH_ACK ; TCB_TIMED_WAIT |
222 | db TH_ACK ; TCPS_TIMED_WAIT |
223 | 223 | ||
224 | 224 | ||
225 | 225 | ||
226 | 226 | ||
227 | 227 | ||
228 | 228 | ||
229 | ;--------------------------------------- |
229 | ;--------------------------------------- |
230 | ; |
230 | ; |
231 | ; The fast way to send an ACK/RST/keepalive segment |
231 | ; The fast way to send an ACK/RST/keepalive segment |
232 | ; |
232 | ; |
233 | ; TCP_respond_socket: |
233 | ; TCP_respond_socket: |
234 | ; |
234 | ; |
235 | ; IN: ebx = socket ptr |
235 | ; IN: ebx = socket ptr |
236 | ; cl = flags |
236 | ; cl = flags |
237 | ; |
237 | ; |
238 | ;-------------------------------------- |
238 | ;-------------------------------------- |
239 | align 4 |
239 | align 4 |
240 | TCP_respond_socket: |
240 | TCP_respond_socket: |
241 | 241 | ||
242 | DEBUGF 1,"TCP_respond_socket\n" |
242 | DEBUGF 1,"TCP_respond_socket\n" |
243 | 243 | ||
244 | ;--------------------- |
244 | ;--------------------- |
245 | ; Create the IP packet |
245 | ; Create the IP packet |
246 | 246 | ||
247 | push cx ebx |
247 | push cx ebx |
248 | mov eax, [ebx + IP_SOCKET.RemoteIP] |
248 | mov eax, [ebx + IP_SOCKET.RemoteIP] |
249 | mov ebx, [ebx + IP_SOCKET.LocalIP] |
249 | mov ebx, [ebx + IP_SOCKET.LocalIP] |
250 | mov ecx, TCP_segment.Data |
250 | mov ecx, TCP_segment.Data |
251 | mov di , IP_PROTO_TCP shl 8 + 128 |
251 | mov di , IP_PROTO_TCP shl 8 + 128 |
252 | call IPv4_output |
252 | call IPv4_output |
253 | test edi, edi |
253 | test edi, edi |
254 | jz .error |
254 | jz .error |
255 | pop esi cx |
255 | pop esi cx |
256 | push edx eax |
256 | push edx eax |
257 | 257 | ||
258 | ;----------------------------------------------- |
258 | ;----------------------------------------------- |
259 | ; Fill in the TCP header by using the socket ptr |
259 | ; Fill in the TCP header by using the socket ptr |
260 | 260 | ||
261 | mov ax, [esi + TCP_SOCKET.LocalPort] |
261 | mov ax, [esi + TCP_SOCKET.LocalPort] |
262 | rol ax, 8 |
262 | rol ax, 8 |
263 | stosw |
263 | stosw |
264 | mov ax, [esi + TCP_SOCKET.RemotePort] |
264 | mov ax, [esi + TCP_SOCKET.RemotePort] |
265 | rol ax, 8 |
265 | rol ax, 8 |
266 | stosw |
266 | stosw |
267 | mov eax, [esi + TCP_SOCKET.SND_NXT] |
267 | mov eax, [esi + TCP_SOCKET.SND_NXT] |
268 | bswap eax |
268 | bswap eax |
269 | stosd |
269 | stosd |
270 | mov eax, [esi + TCP_SOCKET.RCV_NXT] |
270 | mov eax, [esi + TCP_SOCKET.RCV_NXT] |
271 | bswap eax |
271 | bswap eax |
272 | stosd |
272 | stosd |
273 | mov al, 0x50 ; Dataoffset: 20 bytes |
273 | mov al, 0x50 ; Dataoffset: 20 bytes |
274 | stosb |
274 | stosb |
275 | mov al, cl |
275 | mov al, cl |
276 | stosb |
276 | stosb |
277 | ; mov ax, [esi + TCP_SOCKET.RCV_WND] |
277 | ; mov ax, [esi + TCP_SOCKET.RCV_WND] |
278 | ; rol ax, 8 |
278 | ; rol ax, 8 |
279 | mov ax, 0x00a0 ;;;;;;; FIXME |
279 | mov ax, 0x00a0 ;;;;;;; FIXME |
280 | stosw ; window |
280 | stosw ; window |
281 | xor eax, eax |
281 | xor eax, eax |
282 | stosd ; checksum + urgentpointer |
282 | stosd ; checksum + urgentpointer |
283 | 283 | ||
284 | ;--------------------- |
284 | ;--------------------- |
285 | ; Fill in the checksum |
285 | ; Fill in the checksum |
286 | 286 | ||
287 | .checksum: |
287 | .checksum: |
288 | sub edi, TCP_segment.Data |
288 | sub edi, TCP_segment.Data |
289 | mov ecx, TCP_segment.Data |
289 | mov ecx, TCP_segment.Data |
290 | xchg esi, edi |
290 | xchg esi, edi |
291 | TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP) |
291 | TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP) |
292 | mov [esi+TCP_segment.Checksum], dx |
292 | mov [esi+TCP_segment.Checksum], dx |
293 | 293 | ||
294 | ;-------------------- |
294 | ;-------------------- |
295 | ; And send the segment |
295 | ; And send the segment |
296 | 296 | ||
297 | call [ebx + NET_DEVICE.transmit] |
297 | call [ebx + NET_DEVICE.transmit] |
298 | ret |
298 | ret |
299 | 299 | ||
300 | .error: |
300 | .error: |
301 | DEBUGF 1,"TCP_respond failed\n" |
301 | DEBUGF 1,"TCP_respond failed\n" |
302 | add esp, 2+4 |
302 | add esp, 2+4 |
303 | 303 | ||
304 | ret |
304 | ret |
305 | 305 | ||
306 | 306 | ||
307 | 307 | ||
308 | 308 | ||
309 | 309 | ||
310 | 310 | ||
311 | 311 | ||
312 | 312 | ||
313 | ;------------------------- |
313 | ;------------------------- |
314 | ; TCP_respond.segment: |
314 | ; TCP_respond.segment: |
315 | ; |
315 | ; |
316 | ; IN: edx = segment ptr (a previously received segment) |
316 | ; IN: edx = segment ptr (a previously received segment) |
317 | ; cl = flags |
317 | ; cl = flags |
318 | 318 | ||
319 | align 4 |
319 | align 4 |
320 | TCP_respond_segment: |
320 | TCP_respond_segment: |
321 | 321 | ||
322 | DEBUGF 1,"TCP_respond_segment\n" |
322 | DEBUGF 1,"TCP_respond_segment\n" |
323 | 323 | ||
324 | ;--------------------- |
324 | ;--------------------- |
325 | ; Create the IP packet |
325 | ; Create the IP packet |
326 | 326 | ||
327 | push cx edx |
327 | push cx edx |
328 | mov ebx, [edx - 20 + IPv4_Packet.SourceAddress] ;;;; and what if ip packet had options?! |
328 | mov ebx, [edx - 20 + IPv4_Packet.SourceAddress] ;;;; and what if ip packet had options?! |
329 | mov eax, [edx - 20 + IPv4_Packet.DestinationAddress] ;;; |
329 | mov eax, [edx - 20 + IPv4_Packet.DestinationAddress] ;;; |
330 | mov ecx, TCP_segment.Data |
330 | mov ecx, TCP_segment.Data |
331 | mov di , IP_PROTO_TCP shl 8 + 128 |
331 | mov di , IP_PROTO_TCP shl 8 + 128 |
332 | call IPv4_output |
332 | call IPv4_output |
333 | jz .error |
333 | jz .error |
334 | pop esi cx |
334 | pop esi cx |
335 | 335 | ||
336 | push edx eax |
336 | push edx eax |
337 | 337 | ||
338 | ;--------------------------------------------------- |
338 | ;--------------------------------------------------- |
339 | ; Fill in the TCP header by using a received segment |
339 | ; Fill in the TCP header by using a received segment |
340 | 340 | ||
341 | mov ax, [esi + TCP_segment.DestinationPort] |
341 | mov ax, [esi + TCP_segment.DestinationPort] |
342 | rol ax, 8 |
342 | rol ax, 8 |
343 | stosw |
343 | stosw |
344 | mov ax, [esi + TCP_segment.SourcePort] |
344 | mov ax, [esi + TCP_segment.SourcePort] |
345 | rol ax, 8 |
345 | rol ax, 8 |
346 | stosw |
346 | stosw |
347 | mov eax, [esi + TCP_segment.AckNumber] |
347 | mov eax, [esi + TCP_segment.AckNumber] |
348 | bswap eax |
348 | bswap eax |
349 | stosd |
349 | stosd |
350 | xor eax, eax |
350 | xor eax, eax |
351 | stosd |
351 | stosd |
352 | mov al, 0x50 ; Dataoffset: 20 bytes |
352 | mov al, 0x50 ; Dataoffset: 20 bytes |
353 | stosb |
353 | stosb |
354 | mov al, cl |
354 | mov al, cl |
355 | stosb |
355 | stosb |
356 | mov ax, 1280 |
356 | mov ax, 1280 |
357 | rol ax, 8 |
357 | rol ax, 8 |
358 | stosw ; window |
358 | stosw ; window |
359 | xor eax, eax |
359 | xor eax, eax |
360 | stosd ; checksum + urgentpointer |
360 | stosd ; checksum + urgentpointer |
361 | 361 | ||
362 | ;--------------------- |
362 | ;--------------------- |
363 | ; Fill in the checksum |
363 | ; Fill in the checksum |
364 | 364 | ||
365 | .checksum: |
365 | .checksum: |
366 | lea esi, [edi - TCP_segment.Data] |
366 | lea esi, [edi - TCP_segment.Data] |
367 | mov ecx, TCP_segment.Data |
367 | mov ecx, TCP_segment.Data |
368 | TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress) |
368 | TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress) |
369 | mov [esi+TCP_segment.Checksum], dx |
369 | mov [esi+TCP_segment.Checksum], dx |
370 | 370 | ||
371 | ;-------------------- |
371 | ;-------------------- |
372 | ; And send the segment |
372 | ; And send the segment |
373 | 373 | ||
374 | call [ebx + NET_DEVICE.transmit] |
374 | call [ebx + NET_DEVICE.transmit] |
375 | ret |
375 | ret |
376 | 376 | ||
377 | .error: |
377 | .error: |
378 | DEBUGF 1,"TCP_respond failed\n" |
378 | DEBUGF 1,"TCP_respond failed\n" |
379 | add esp, 2+4 |
379 | add esp, 2+4 |
380 | 380 | ||
381 | ret |
381 | ret |