Rev 1318 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1171 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
3 | ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; |
||
4 | ;; Distributed under terms of the GNU General Public License ;; |
||
5 | ;; ;; |
||
6 | ;; STACK.INC ;; |
||
7 | ;; ;; |
||
8 | ;; BASIC TCP/IP stack for KolibriOS ;; |
||
9 | ;; ;; |
||
10 | ;; Written by hidnplayr@kolibrios.org ;; |
||
11 | ;; ;; |
||
12 | ;; based on the work of Mike Hibbett, mikeh@oceanfree.net ;; |
||
13 | ;; but also Paolo Franchetti ;; |
||
14 | ;; ;; |
||
15 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
16 | ;; Version 2, June 1991 ;; |
||
17 | ;; ;; |
||
18 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
1159 | hidnplayr | 19 | |
1206 | hidnplayr | 20 | $Revision: 1473 $ |
1159 | hidnplayr | 21 | |
1473 | hidnplayr | 22 | __DEBUG_LEVEL_OLD__ equ __DEBUG_LEVEL__ |
23 | __DEBUG_LEVEL__ equ 1 ; this sets the debug level for network part of kernel |
||
24 | |||
1159 | hidnplayr | 25 | uglobal |
26 | last_1sTick db ? |
||
27 | last_1hsTick dd ? |
||
28 | endg |
||
29 | |||
1259 | hidnplayr | 30 | MAX_NET_DEVICES equ 16 |
1473 | hidnplayr | 31 | QUEUE_BEFORE_SENDING equ 0 ; 1 or 0 (enable or disable) currently only affects ethernet |
1159 | hidnplayr | 32 | |
1185 | hidnplayr | 33 | MIN_EPHEMERAL_PORT equ 49152 |
34 | MAX_EPHEMERAL_PORT equ 61000 |
||
1159 | hidnplayr | 35 | |
1473 | hidnplayr | 36 | ETHER equ 1337 ; TODO: find another value for this (how does it work in posix ?) |
1185 | hidnplayr | 37 | ETHER_ARP equ 0x0608 |
38 | |||
1254 | hidnplayr | 39 | AF_UNSPEC equ 0 |
1249 | hidnplayr | 40 | AF_UNIX equ 1 |
1159 | hidnplayr | 41 | AF_INET4 equ 2 |
42 | ;AF_AX25 equ 3 |
||
43 | ;AF_IPX equ 4 |
||
44 | ;AF_APPLETALK equ 5 |
||
45 | ;AF_NETROM equ 6 |
||
46 | ;AF_BRIDGE equ 7 |
||
47 | ;AF_AAL5 equ 8 |
||
48 | ;AF_X25 equ 9 |
||
49 | ;AF_INET6 equ 10 |
||
50 | ;AF_MAX equ 12 |
||
51 | |||
52 | IP_PROTO_IP equ 0 |
||
53 | IP_PROTO_ICMP equ 1 |
||
54 | IP_PROTO_TCP equ 6 |
||
55 | IP_PROTO_UDP equ 17 |
||
56 | |||
1200 | hidnplayr | 57 | ; Socket types |
58 | SOCK_STREAM = 1 |
||
59 | SOCK_DGRAM = 2 |
||
60 | SOCK_RAW = 3 |
||
61 | |||
1254 | hidnplayr | 62 | TCB_LISTEN equ 1 |
63 | TCB_SYN_SENT equ 2 |
||
64 | TCB_SYN_RECEIVED equ 3 |
||
65 | TCB_ESTABLISHED equ 4 |
||
66 | TCB_FIN_WAIT_1 equ 5 |
||
67 | TCB_FIN_WAIT_2 equ 6 |
||
68 | TCB_CLOSE_WAIT equ 7 |
||
69 | TCB_CLOSING equ 8 |
||
70 | TCB_LAST_ACK equ 9 |
||
71 | TCB_TIMED_WAIT equ 10 |
||
72 | TCB_CLOSED equ 11 |
||
1159 | hidnplayr | 73 | |
1254 | hidnplayr | 74 | TH_FIN equ 1 shl 0 |
75 | TH_SYN equ 1 shl 1 |
||
76 | TH_RST equ 1 shl 2 |
||
77 | TH_PUSH equ 1 shl 3 |
||
78 | TH_ACK equ 1 shl 4 |
||
79 | TH_URG equ 1 shl 5 |
||
80 | |||
81 | |||
82 | macro inc_INET reg { |
||
83 | |||
1256 | clevermous | 84 | add byte [reg + 3], 1 |
1254 | hidnplayr | 85 | adc byte [reg + 2], 0 |
86 | adc byte [reg + 1], 0 |
||
1256 | clevermous | 87 | adc byte [reg], 0 |
1254 | hidnplayr | 88 | |
89 | } |
||
90 | |||
91 | |||
92 | macro add_INET reg { |
||
1256 | clevermous | 93 | add byte [reg + 3], cl |
94 | adc byte [reg + 2], ch |
||
95 | adc byte [reg + 1], 0 |
||
96 | adc byte [reg], 0 |
||
1254 | hidnplayr | 97 | rol ecx, 16 |
1256 | clevermous | 98 | add byte [reg + 1], cl |
99 | adc byte [reg], ch |
||
1254 | hidnplayr | 100 | rol ecx, 16 |
101 | } |
||
102 | |||
1318 | hidnplayr | 103 | |
104 | macro pseudo_random reg { |
||
105 | |||
106 | add reg, [esp] |
||
107 | rol reg, 5 |
||
108 | xor reg, [timer_ticks] |
||
109 | imul reg, 214013 |
||
110 | xor reg, 0xdeadbeef |
||
111 | rol reg, 9 |
||
112 | |||
113 | pushd reg |
||
114 | mov word [esp], 0x8080 ; kernel heap start addr (os_stack) |
||
115 | xor reg, [esp] |
||
116 | add esp, 4 |
||
117 | |||
118 | } |
||
119 | |||
1159 | hidnplayr | 120 | include "queue.inc" |
1187 | hidnplayr | 121 | include "ARP.inc" |
122 | include "IPv4.inc" |
||
1159 | hidnplayr | 123 | include "ethernet.inc" |
124 | include "socket.inc" |
||
1249 | hidnplayr | 125 | include "tcp.inc" |
1185 | hidnplayr | 126 | include "udp.inc" |
127 | include "icmp.inc" |
||
1159 | hidnplayr | 128 | |
1257 | hidnplayr | 129 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 130 | ; |
131 | ; stack_init |
||
132 | ; |
||
133 | ; This function calls all network init procedures |
||
134 | ; |
||
135 | ; IN: / |
||
136 | ; OUT: / |
||
137 | ; |
||
1257 | hidnplayr | 138 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 139 | align 4 |
140 | stack_init: |
||
141 | |||
142 | call ETH_init |
||
143 | call IPv4_init |
||
144 | call ARP_init |
||
145 | call UDP_init |
||
1249 | hidnplayr | 146 | call TCP_init |
1159 | hidnplayr | 147 | call ICMP_init |
148 | call socket_init |
||
149 | |||
1254 | hidnplayr | 150 | mov al, 0 ; set up 1s timer |
1159 | hidnplayr | 151 | out 0x70, al |
152 | in al, 0x71 |
||
153 | mov [last_1sTick], al |
||
154 | |||
155 | ret |
||
156 | |||
157 | |||
158 | |||
1257 | hidnplayr | 159 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 160 | ; |
161 | ; stack_handler |
||
162 | ; |
||
163 | ; This function calls all network init procedures |
||
164 | ; |
||
165 | ; IN: / |
||
166 | ; OUT: / |
||
167 | ; |
||
1257 | hidnplayr | 168 | ;----------------------------------------------------------------- |
1159 | hidnplayr | 169 | align 4 |
170 | stack_handler: |
||
171 | |||
1257 | hidnplayr | 172 | cmp [ETH_RUNNING], 0 |
173 | je .exit |
||
1159 | hidnplayr | 174 | |
1318 | hidnplayr | 175 | ; Test for 10ms tick |
1257 | hidnplayr | 176 | mov eax, [timer_ticks] |
177 | cmp eax, [last_1hsTick] |
||
178 | je .exit |
||
1159 | hidnplayr | 179 | |
1257 | hidnplayr | 180 | mov [last_1hsTick], eax |
1159 | hidnplayr | 181 | |
1257 | hidnplayr | 182 | call ETH_handler ; handle all queued ethernet packets |
1259 | hidnplayr | 183 | if QUEUE_BEFORE_SENDING |
1257 | hidnplayr | 184 | call ETH_send_queued |
1259 | hidnplayr | 185 | end if |
1257 | hidnplayr | 186 | call TCP_send_queued |
1249 | hidnplayr | 187 | |
1159 | hidnplayr | 188 | .sec_tick: |
189 | |||
1257 | hidnplayr | 190 | ; Test for 1 second tick |
191 | mov al, 0 |
||
192 | out 0x70, al |
||
193 | in al, 0x71 |
||
194 | cmp al, [last_1sTick] |
||
195 | je .exit |
||
1159 | hidnplayr | 196 | |
1257 | hidnplayr | 197 | mov [last_1sTick], al |
1159 | hidnplayr | 198 | |
1257 | hidnplayr | 199 | call ARP_decrease_entry_ttls |
200 | call IPv4_decrease_fragment_ttls |
||
201 | call TCP_decrease_socket_ttls |
||
1159 | hidnplayr | 202 | |
203 | .exit: |
||
1257 | hidnplayr | 204 | ret |
1159 | hidnplayr | 205 | |
206 | |||
1249 | hidnplayr | 207 | ;----------------------------------------------------------------- |
208 | ; |
||
209 | ; checksum_1 |
||
210 | ; |
||
211 | ; This is the first of two functions needed to calculate the TCP checksum. |
||
212 | ; |
||
1473 | hidnplayr | 213 | ; IN: edx = start offset for semi-checksum |
1249 | hidnplayr | 214 | ; esi = pointer to data |
215 | ; ecx = data size |
||
216 | ; OUT: edx = semi-checksum |
||
217 | ; |
||
1473 | hidnplayr | 218 | ; |
219 | ; Code was optimized by diamond |
||
220 | ; |
||
1249 | hidnplayr | 221 | ;----------------------------------------------------------------- |
222 | align 4 |
||
223 | checksum_1: |
||
1159 | hidnplayr | 224 | |
1249 | hidnplayr | 225 | shr ecx, 1 |
226 | pushf |
||
1473 | hidnplayr | 227 | jz .no_2 |
1159 | hidnplayr | 228 | |
1473 | hidnplayr | 229 | shr ecx, 1 |
230 | pushf |
||
231 | jz .no_4 |
||
232 | |||
233 | shr ecx, 1 |
||
234 | pushf |
||
235 | jz .no_8 |
||
236 | |||
237 | .loop: |
||
238 | add dl, [esi+1] |
||
239 | adc dh, [esi+0] |
||
240 | |||
241 | adc dl, [esi+3] |
||
242 | adc dh, [esi+2] |
||
243 | |||
244 | adc dl, [esi+5] |
||
245 | adc dh, [esi+4] |
||
246 | |||
247 | adc dl, [esi+7] |
||
248 | adc dh, [esi+6] |
||
249 | |||
250 | adc edx, 0 |
||
251 | add esi, 8 |
||
252 | |||
253 | dec ecx |
||
254 | jnz .loop |
||
255 | |||
256 | adc edx, 0 |
||
257 | |||
258 | .no_8: |
||
1249 | hidnplayr | 259 | popf |
1473 | hidnplayr | 260 | jnc .no_4 |
261 | |||
262 | add dl, [esi+1] |
||
263 | adc dh, [esi+0] |
||
264 | |||
265 | adc dl, [esi+3] |
||
266 | adc dh, [esi+2] |
||
267 | |||
268 | adc edx, 0 |
||
269 | add esi, 4 |
||
270 | |||
271 | .no_4: |
||
272 | popf |
||
273 | jnc .no_2 |
||
274 | |||
275 | add dl, [esi+1] |
||
276 | adc dh, [esi+0] |
||
277 | |||
278 | adc edx, 0 |
||
279 | |||
280 | inc ecx |
||
281 | inc ecx |
||
282 | |||
283 | .no_2: |
||
284 | popf |
||
1249 | hidnplayr | 285 | jnc .end |
1159 | hidnplayr | 286 | |
1473 | hidnplayr | 287 | add dh, [esi+0] |
1251 | clevermous | 288 | adc edx, 0 |
1473 | hidnplayr | 289 | .end: |
290 | ret |
||
1159 | hidnplayr | 291 | |
1249 | hidnplayr | 292 | |
1473 | hidnplayr | 293 | |
294 | |||
295 | |||
296 | ;IN: 12 bytes of pseudoheader pushed onto the stack |
||
297 | ; edx = start offset |
||
298 | ; |
||
299 | ; OUT: pseudochecksum in edx |
||
300 | |||
301 | |||
302 | align 4 |
||
303 | checksum_pseudoheader: |
||
304 | |||
305 | add dl, [esp+5] |
||
306 | adc dh, [esp+4] |
||
307 | |||
308 | adc dl, [esp+7] |
||
309 | adc dh, [esp+6] |
||
310 | |||
311 | adc dl, [esp+9] |
||
312 | adc dh, [esp+8] |
||
313 | |||
314 | adc dl, [esp+11] |
||
315 | adc dh, [esp+10] |
||
316 | |||
317 | adc dl, [esp+13] |
||
318 | adc dh, [esp+12] |
||
319 | |||
320 | adc dl, [esp+15] |
||
321 | adc dh, [esp+14] |
||
322 | |||
323 | adc edx,0 |
||
324 | ret 12 |
||
325 | |||
326 | |||
327 | |||
328 | |||
329 | |||
330 | align 4 |
||
331 | checksum_ip_header: |
||
332 | |||
333 | ; This is the fast procedure to create or check a IP header without options |
||
334 | ; |
||
335 | ; To create a new checksum, the checksum field must be set to 0 before computation |
||
336 | ; |
||
337 | ; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct |
||
338 | |||
339 | xor edx, edx |
||
340 | |||
341 | add dl, [esi+1] |
||
342 | adc dh, [esi+0] |
||
343 | |||
344 | adc dl, [esi+3] |
||
345 | adc dh, [esi+2] |
||
346 | |||
347 | adc dl, [esi+5] |
||
348 | adc dh, [esi+4] |
||
349 | |||
350 | adc dl, [esi+7] |
||
351 | adc dh, [esi+6] |
||
352 | |||
353 | adc dl, [esi+9] |
||
354 | adc dh, [esi+8] |
||
355 | |||
356 | ; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation |
||
357 | |||
358 | adc dl, [esi+13] |
||
359 | adc dh, [esi+12] |
||
360 | |||
361 | adc dl, [esi+15] |
||
362 | adc dh, [esi+14] |
||
363 | |||
364 | adc dl, [esi+17] |
||
365 | adc dh, [esi+16] |
||
366 | |||
367 | adc dl, [esi+19] |
||
368 | adc dh, [esi+18] |
||
369 | |||
370 | adc edx, 0 |
||
371 | |||
372 | call checksum_2 |
||
373 | |||
374 | neg word [esi+10] ; zero will stay zero so we jsut get the checksum |
||
375 | add word [esi+10], dx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :) |
||
376 | |||
1249 | hidnplayr | 377 | ret |
378 | |||
379 | |||
1473 | hidnplayr | 380 | |
381 | |||
382 | |||
383 | |||
384 | |||
385 | |||
386 | align 4 |
||
387 | checksum_udp: |
||
388 | |||
389 | ; This is the fast procedure to create or check a IP header without options |
||
390 | ; |
||
391 | ; To create a new checksum, the checksum field must be set to 0 before computation |
||
392 | ; |
||
393 | ; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct |
||
394 | |||
395 | xor edx, edx |
||
396 | |||
397 | add dl, [esi+1] |
||
398 | adc dh, [esi+0] |
||
399 | |||
400 | adc dl, [esi+3] |
||
401 | adc dh, [esi+2] |
||
402 | |||
403 | adc dl, [esi+5] |
||
404 | adc dh, [esi+4] |
||
405 | |||
406 | adc dl, [esi+7] |
||
407 | adc dh, [esi+6] |
||
408 | |||
409 | adc dl, [esi+9] |
||
410 | adc dh, [esi+8] |
||
411 | |||
412 | ; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation |
||
413 | |||
414 | adc dl, [esi+13] |
||
415 | adc dh, [esi+12] |
||
416 | |||
417 | adc dl, [esi+15] |
||
418 | adc dh, [esi+14] |
||
419 | |||
420 | adc dl, [esi+17] |
||
421 | adc dh, [esi+16] |
||
422 | |||
423 | adc dl, [esi+19] |
||
424 | adc dh, [esi+18] |
||
425 | |||
426 | adc edx, 0 |
||
427 | |||
428 | call checksum_2 |
||
429 | |||
430 | neg word [esi+10] ; zero will stay zero so we jsut get the checksum |
||
431 | add word [esi+10], dx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :) |
||
432 | |||
433 | ret |
||
434 | |||
435 | |||
436 | |||
1249 | hidnplayr | 437 | ;----------------------------------------------------------------- |
438 | ; |
||
439 | ; checksum_2 |
||
440 | ; |
||
441 | ; This function calculates the final ip/tcp/udp checksum for you |
||
442 | ; |
||
443 | ; IN: edx = semi-checksum |
||
444 | ; OUT: dx = checksum (in INET byte order) |
||
445 | ; |
||
446 | ;----------------------------------------------------------------- |
||
447 | align 4 |
||
448 | checksum_2: |
||
449 | |||
450 | mov ecx, edx |
||
451 | shr ecx, 16 |
||
452 | and edx, 0xffff |
||
453 | add edx, ecx |
||
454 | mov eax, edx |
||
455 | shr eax, 16 |
||
456 | add edx, eax |
||
457 | |||
458 | not dx |
||
459 | jnz .not_zero |
||
460 | dec dx |
||
461 | .not_zero: |
||
462 | xchg dl, dh |
||
463 | |||
464 | DEBUGF 1,"Checksum: %x\n",dx |
||
465 | |||
466 | ret |
||
467 | |||
468 | |||
469 | |||
1159 | hidnplayr | 470 | ;---------------------------------------------------------------- |
471 | ; |
||
1171 | hidnplayr | 472 | ; System function to work with network devices (73) |
1159 | hidnplayr | 473 | ; |
474 | ;---------------------------------------------------------------- |
||
475 | align 4 |
||
476 | sys_network: |
||
477 | |||
1196 | hidnplayr | 478 | cmp ebx, -1 |
479 | jne @f |
||
480 | |||
481 | mov eax, [ETH_RUNNING] |
||
482 | jmp .return |
||
483 | |||
484 | @@: |
||
1159 | hidnplayr | 485 | cmp bh, MAX_NET_DEVICES ; Check if device number exists |
486 | jge .doesnt_exist |
||
487 | |||
488 | mov esi, ebx |
||
489 | and esi, 0x0000ff00 |
||
490 | shr esi, 6 |
||
491 | |||
492 | cmp dword [esi + ETH_DRV_LIST], 0 ; check if driver is running |
||
493 | je .doesnt_exist |
||
494 | |||
495 | test bl, bl ; 0 = Get device type (ethernet/token ring/...) |
||
496 | jnz @f |
||
1196 | hidnplayr | 497 | ; todo |
1192 | hidnplayr | 498 | xor eax, eax |
499 | jmp .return |
||
1159 | hidnplayr | 500 | |
501 | |||
502 | @@: |
||
503 | dec bl ; 1 = Get device name |
||
504 | jnz @f |
||
505 | |||
506 | mov esi, [esi + ETH_DRV_LIST] |
||
507 | mov esi, [esi + ETH_DEVICE.name] |
||
508 | mov edi, ecx |
||
509 | |||
510 | mov ecx, 64 ; max length |
||
511 | repnz movsb |
||
512 | |||
1192 | hidnplayr | 513 | xor eax, eax |
514 | jmp .return |
||
1159 | hidnplayr | 515 | |
1192 | hidnplayr | 516 | @@: |
1159 | hidnplayr | 517 | |
1192 | hidnplayr | 518 | dec bl ; 2 = Reset the device |
519 | jnz @f |
||
520 | |||
521 | mov esi, [esi + ETH_DRV_LIST] |
||
522 | call [esi + ETH_DEVICE.reset] |
||
523 | jmp .return |
||
524 | |||
1159 | hidnplayr | 525 | @@: |
1192 | hidnplayr | 526 | |
527 | dec bl ; 3 = Stop driver for this device |
||
528 | jnz @f |
||
529 | |||
530 | mov esi, [esi + ETH_DRV_LIST] |
||
531 | call [esi + ETH_DEVICE.unload] |
||
532 | jmp .return |
||
533 | |||
534 | @@: |
||
1249 | hidnplayr | 535 | dec bl ; 4 = Get driver pointer |
536 | jnz @f |
||
1192 | hidnplayr | 537 | |
1249 | hidnplayr | 538 | ; ..; |
539 | |||
540 | |||
541 | @@: |
||
542 | ; ... ; 5 Get driver name |
||
543 | |||
1159 | hidnplayr | 544 | .doesnt_exist: |
545 | DEBUGF 1,"sys_network: invalid device/function specified!\n" |
||
546 | mov eax, -1 |
||
547 | |||
1192 | hidnplayr | 548 | .return: |
549 | mov [esp+28+4], eax |
||
1159 | hidnplayr | 550 | ret |
551 | |||
552 | |||
553 | ;---------------------------------------------------------------- |
||
554 | ; |
||
1171 | hidnplayr | 555 | ; System Function To work with Protocols (75) |
1159 | hidnplayr | 556 | ; |
557 | ;---------------------------------------------------------------- |
||
558 | align 4 |
||
559 | sys_protocols: |
||
560 | cmp bh, MAX_NET_DEVICES ; Check if device number exists |
||
561 | jge .doesnt_exist |
||
562 | |||
563 | mov esi, ebx |
||
564 | and esi, 0x0000ff00 |
||
565 | shr esi, 6 |
||
1171 | hidnplayr | 566 | cmp dword [esi + ETH_DRV_LIST], 0 ; check if driver is running TODO: check other lists too |
1159 | hidnplayr | 567 | je .doesnt_exist |
568 | |||
569 | push .return ; return address (we will be using jumps instead of calls) |
||
570 | |||
571 | mov eax, ebx ; set ax to protocol number |
||
572 | shr eax, 16 ; |
||
573 | |||
574 | cmp ax , IP_PROTO_IP |
||
575 | je IPv4_API |
||
576 | |||
577 | cmp ax , IP_PROTO_ICMP |
||
578 | je ICMP_API |
||
579 | |||
580 | cmp ax , IP_PROTO_UDP |
||
581 | je UDP_API |
||
582 | |||
1171 | hidnplayr | 583 | cmp ax , IP_PROTO_TCP |
1254 | hidnplayr | 584 | je TCP_API |
1159 | hidnplayr | 585 | |
1171 | hidnplayr | 586 | cmp ax , ETHER_ARP |
1159 | hidnplayr | 587 | je ARP_API |
588 | |||
1185 | hidnplayr | 589 | cmp ax , ETHER |
1159 | hidnplayr | 590 | je ETH_API |
591 | |||
1171 | hidnplayr | 592 | add esp, 4 ; if we reached here, no function was called, so we need to balance stack |
1159 | hidnplayr | 593 | |
594 | .doesnt_exist: |
||
1171 | hidnplayr | 595 | DEBUGF 1,"sys_protocols: protocol %u doesnt exist on device %u!\n",ax, bh |
1159 | hidnplayr | 596 | mov eax, -1 |
597 | |||
598 | .return: |
||
1171 | hidnplayr | 599 | mov [esp+28+4], eax |
1257 | hidnplayr | 600 | ret |
1473 | hidnplayr | 601 | |
602 | |||
603 | __DEBUG_LEVEL__ equ __DEBUG_LEVEL_OLD__ |