Subversion Repositories Kolibri OS

Rev

Rev 5015 | Rev 5522 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
3545 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  IPv4.INC                                                       ;;
7
;;                                                                 ;;
8
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
9
;;                                                                 ;;
10
;;  Based on the work of [Johnny_B] and [smb]                      ;;
11
;;                                                                 ;;
12
;;    Written by hidnplayr@kolibrios.org                           ;;
13
;;                                                                 ;;
14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
15
;;             Version 2, June 1991                                ;;
16
;;                                                                 ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
 
4850 mario79 19
$Revision: 5363 $
3545 hidnplayr 20
 
4053 hidnplayr 21
IPv4_MAX_FRAGMENTS              = 64
4387 hidnplayr 22
IPv4_MAX_ROUTES                 = 64
3545 hidnplayr 23
 
4387 hidnplayr 24
IPv4_ROUTE_FLAG_UP              = 1 shl 0
25
IPv4_ROUTE_FLAG_GATEWAY         = 1 shl 1
26
IPv4_ROUTE_FLAG_HOST            = 1 shl 2
27
IPv4_ROUTE_FLAG_D               = 1 shl 3       ; Route was created by a redirect
28
IPv4_ROUTE_FLAG_M               = 1 shl 4       ; Route was modified by a redirect
29
 
3545 hidnplayr 30
struct  IPv4_header
31
 
32
        VersionAndIHL           db ?    ; Version[0-3 bits] and IHL(header length)[4-7 bits]
33
        TypeOfService           db ?    ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0]
34
        TotalLength             dw ?
35
        Identification          dw ?
36
        FlagsAndFragmentOffset  dw ?    ; Flags[0-2] and FragmentOffset[3-15]
37
        TimeToLive              db ?    ;
38
        Protocol                db ?
39
        HeaderChecksum          dw ?
40
        SourceAddress           dd ?
41
        DestinationAddress      dd ?
42
 
43
ends
44
 
4052 hidnplayr 45
struct  IPv4_FRAGMENT_slot
3545 hidnplayr 46
 
47
        ttl                     dw ?    ; Time to live for this entry, 0 for empty slot's
48
        id                      dw ?    ; Identification field from IP header
49
        SrcIP                   dd ?    ; .. from IP header
50
        DstIP                   dd ?    ; .. from IP header
51
        ptr                     dd ?    ; Pointer to first packet
52
 
53
ends
54
 
4052 hidnplayr 55
struct  IPv4_FRAGMENT_entry             ; This structure will replace the ethernet header in fragmented ip packets
3545 hidnplayr 56
 
57
        PrevPtr                 dd ?    ; Pointer to previous fragment entry  (-1 for first packet)
58
        NextPtr                 dd ?    ; Pointer to next fragment entry (-1 for last packet)
59
        Owner                   dd ?    ; Pointer to structure of driver
60
                                rb 2    ; to match ethernet header size         ;;; FIXME
61
                                        ; Ip header begins here (we will need the IP header to re-construct the complete packet)
62
ends
63
 
4387 hidnplayr 64
struct  IPv4_ROUTE
3545 hidnplayr 65
 
4387 hidnplayr 66
        Destination             dd ?
67
        Gateway                 dd ?
68
        Flags                   dd ?
69
        Use                     dd ?
70
        Interface               dd ?
71
 
72
ends
73
 
74
 
3698 hidnplayr 75
uglobal
3545 hidnplayr 76
align 4
77
 
3600 hidnplayr 78
        IP_LIST                 rd NET_DEVICES_MAX
79
        SUBNET_LIST             rd NET_DEVICES_MAX
80
        DNS_LIST                rd NET_DEVICES_MAX
81
        GATEWAY_LIST            rd NET_DEVICES_MAX
82
        BROADCAST_LIST          rd NET_DEVICES_MAX
3545 hidnplayr 83
 
4052 hidnplayr 84
        IPv4_packets_tx         rd NET_DEVICES_MAX
85
        IPv4_packets_rx         rd NET_DEVICES_MAX
86
        IPv4_packets_dumped     rd NET_DEVICES_MAX
3545 hidnplayr 87
 
4052 hidnplayr 88
        IPv4_FRAGMENT_LIST      rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
3698 hidnplayr 89
 
4387 hidnplayr 90
        IPv4_ROUTES             rd IPv4_MAX_ROUTES * sizeof.IPv4_ROUTE
91
 
3545 hidnplayr 92
endg
93
 
94
 
95
;-----------------------------------------------------------------
96
;
97
; IPv4_init
98
;
99
;  This function resets all IP variables
100
;
101
;-----------------------------------------------------------------
102
macro   IPv4_init {
103
 
104
        xor     eax, eax
105
        mov     edi, IP_LIST
4052 hidnplayr 106
        mov     ecx, 7*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_MAX_FRAGMENTS)/4
3711 clevermous 107
        rep stosd
3545 hidnplayr 108
 
109
}
110
 
111
 
112
;-----------------------------------------------------------------
113
;
114
; Decrease TimeToLive of all fragment slots
115
;
116
;-----------------------------------------------------------------
117
macro IPv4_decrease_fragment_ttls {
118
 
119
local   .loop, .next
120
 
4052 hidnplayr 121
        mov     esi, IPv4_FRAGMENT_LIST
122
        mov     ecx, IPv4_MAX_FRAGMENTS
3545 hidnplayr 123
  .loop:
4052 hidnplayr 124
        cmp     [esi + IPv4_FRAGMENT_slot.ttl], 0
3545 hidnplayr 125
        je      .next
4052 hidnplayr 126
        dec     [esi + IPv4_FRAGMENT_slot.ttl]
3545 hidnplayr 127
        jz      .died
128
  .next:
4052 hidnplayr 129
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 130
        dec     ecx
131
        jnz     .loop
132
        jmp     .done
133
 
134
  .died:
3556 hidnplayr 135
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4 Fragment slot timed-out!\n"
3545 hidnplayr 136
;;; TODO: clear all entry's of timed-out slot
137
        jmp     .next
138
 
139
  .done:
140
}
141
 
142
 
143
 
144
macro IPv4_checksum ptr {
145
 
146
; This is the fast procedure to create or check an IP header without options
147
; To create a new checksum, the checksum field must be set to 0 before computation
148
; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
149
 
150
        push    ebx
151
        xor     ebx, ebx
152
        add     bl, [ptr+1]
153
        adc     bh, [ptr+0]
154
 
155
        adc     bl, [ptr+3]
156
        adc     bh, [ptr+2]
157
 
158
        adc     bl, [ptr+5]
159
        adc     bh, [ptr+4]
160
 
161
        adc     bl, [ptr+7]
162
        adc     bh, [ptr+6]
163
 
164
        adc     bl, [ptr+9]
165
        adc     bh, [ptr+8]
166
 
167
; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
168
 
169
        adc     bl, [ptr+13]
170
        adc     bh, [ptr+12]
171
 
172
        adc     bl, [ptr+15]
173
        adc     bh, [ptr+14]
174
 
175
        adc     bl, [ptr+17]
176
        adc     bh, [ptr+16]
177
 
178
        adc     bl, [ptr+19]
179
        adc     bh, [ptr+18]
180
 
181
        adc     ebx, 0
182
 
183
        push    ecx
184
        mov     ecx, ebx
185
        shr     ecx, 16
186
        and     ebx, 0xffff
187
        add     ebx, ecx
188
 
189
        mov     ecx, ebx
190
        shr     ecx, 16
191
        add     ebx, ecx
192
 
193
        not     bx
194
        jnz     .not_zero
195
        dec     bx
196
  .not_zero:
197
        xchg    bl, bh
198
        pop     ecx
199
 
200
        neg     word [ptr+10]           ; zero will stay zero so we just get the checksum
201
        add     word [ptr+10], bx       ;  , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
202
        pop     ebx
203
 
204
}
205
 
206
 
207
 
208
;-----------------------------------------------------------------
209
;
210
; IPv4_input:
211
;
212
;  Will check if IPv4 Packet isnt damaged
213
;  and call appropriate handler. (TCP/UDP/ICMP/..)
214
;
215
;  It will also re-construct fragmented packets
216
;
217
;  IN:  Pointer to buffer in [esp]
218
;       size of buffer in [esp+4]
219
;       pointer to device struct in ebx
220
;       pointer to IPv4 header in edx
221
;       size of IPv4 packet in ecx
222
;  OUT: /
223
;
224
;-----------------------------------------------------------------
225
align 4
226
IPv4_input:                                                     ; TODO: add IPv4 raw sockets support
227
 
3556 hidnplayr 228
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input, packet from: %u.%u.%u.%u ",\
3545 hidnplayr 229
        [edx + IPv4_header.SourceAddress + 0]:1,[edx + IPv4_header.SourceAddress + 1]:1,\
230
        [edx + IPv4_header.SourceAddress + 2]:1,[edx + IPv4_header.SourceAddress + 3]:1
3556 hidnplayr 231
        DEBUGF  DEBUG_NETWORK_VERBOSE, "to: %u.%u.%u.%u\n",\
3545 hidnplayr 232
        [edx + IPv4_header.DestinationAddress + 0]:1,[edx + IPv4_header.DestinationAddress + 1]:1,\
233
        [edx + IPv4_header.DestinationAddress + 2]:1,[edx + IPv4_header.DestinationAddress + 3]:1
234
 
235
;-------------------------------
236
; re-calculate the checksum
237
 
238
        IPv4_checksum edx
239
        jnz     .dump                                           ; if checksum isn't valid then dump packet
240
 
3556 hidnplayr 241
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Checksum ok\n"
3545 hidnplayr 242
 
243
;-----------------------------------
244
; Check if destination IP is correct
245
 
3643 hidnplayr 246
        call    NET_ptr_to_num4
3545 hidnplayr 247
 
248
        ; check if it matches local ip (Using RFC1122 strong end system model)
249
 
250
        mov     eax, [edx + IPv4_header.DestinationAddress]
251
        cmp     eax, [IP_LIST + edi]
252
        je      .ip_ok
253
 
254
        ; check for broadcast (IP or (not SUBNET))
255
 
256
        cmp     eax, [BROADCAST_LIST + edi]
257
        je      .ip_ok
258
 
259
        ; or a special broadcast (255.255.255.255)
260
 
261
        cmp     eax, 0xffffffff
262
        je      .ip_ok
263
 
264
        ; maybe it's a multicast (224.0.0.0/4)
265
 
266
        and     eax, 0x0fffffff
267
        cmp     eax, 224
268
        je      .ip_ok
269
 
4976 hidnplayr 270
        ; maybe we just dont have an IP yet and should accept everything on the IP level
3545 hidnplayr 271
 
4976 hidnplayr 272
        cmp     [IP_LIST + edi], 0
3545 hidnplayr 273
        je      .ip_ok
274
 
275
        ; or it's just not meant for us.. :(
276
 
3556 hidnplayr 277
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destination address does not match!\n"
3545 hidnplayr 278
        jmp     .dump
279
 
280
;------------------------
281
; Now we can update stats
282
 
283
  .ip_ok:
4052 hidnplayr 284
        inc     [IPv4_packets_rx + edi]
3545 hidnplayr 285
 
286
;----------------------------------
287
; Check if the packet is fragmented
288
 
289
        test    [edx + IPv4_header.FlagsAndFragmentOffset], 1 shl 5     ; Is 'more fragments' flag set ?
290
        jnz     .has_fragments                                          ; If so, we definately have a fragmented packet
291
 
292
        test    [edx + IPv4_header.FlagsAndFragmentOffset], 0xff1f      ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets
293
        jnz     .is_last_fragment
294
 
295
;-------------------------------------------------------------------
296
; No, it's just a regular IP packet, pass it to the higher protocols
297
 
298
  .handle_it:                                                   ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
299
 
300
        movzx   esi, [edx + IPv4_header.VersionAndIHL]          ; Calculate Header length by using IHL field
301
        and     esi, 0x0000000f                                 ;
302
        shl     esi, 2                                          ;
303
 
304
        movzx   ecx, [edx + IPv4_header.TotalLength]            ; Calculate length of encapsulated Packet
305
        xchg    cl, ch                                          ;
306
        sub     ecx, esi                                        ;
307
 
308
        lea     edi, [edx + IPv4_header.SourceAddress]          ; make edi ptr to source and dest IPv4 address
309
        mov     al, [edx + IPv4_header.Protocol]
310
        add     esi, edx                                        ; make esi ptr to data
311
 
312
        cmp     al, IP_PROTO_TCP
313
        je      TCP_input
314
 
315
        cmp     al, IP_PROTO_UDP
316
        je      UDP_input
317
 
318
        cmp     al, IP_PROTO_ICMP
319
        je      ICMP_input
320
 
3556 hidnplayr 321
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: unknown protocol %u\n", al
3545 hidnplayr 322
 
323
  .dump:
3556 hidnplayr 324
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n"
4052 hidnplayr 325
        inc     [IPv4_packets_dumped]                           ; FIXME: use correct interface
3861 hidnplayr 326
        call    NET_packet_free
3545 hidnplayr 327
        add     esp, 4                                          ; pop (balance stack)
328
        ret
329
 
330
 
331
;---------------------------
332
; Fragmented packet handler
333
 
334
 
335
  .has_fragments:
336
        movzx   eax, [edx + IPv4_header.FlagsAndFragmentOffset]
337
        xchg    al, ah
338
        shl     ax, 3
339
 
4258 hidnplayr 340
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx
3545 hidnplayr 341
 
342
        test    ax, ax                                          ; Is this the first packet of the fragment?
343
        jz      .is_first_fragment
344
 
345
 
346
;-------------------------------------------------------
347
; We have a fragmented IP packet, but it's not the first
348
 
3556 hidnplayr 349
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Middle fragment packet received!\n"
3545 hidnplayr 350
 
351
        call    IPv4_find_fragment_slot
352
        cmp     esi, -1
353
        je      .dump
354
 
4052 hidnplayr 355
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; Reset the ttl
356
        mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]
3545 hidnplayr 357
        or      edi, -1
358
  .find_last_entry:                                             ; The following routine will try to find the last entry
4052 hidnplayr 359
        cmp     edi, [esi + IPv4_FRAGMENT_entry.PrevPtr]
3545 hidnplayr 360
        jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
361
        mov     edi, esi
4052 hidnplayr 362
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3545 hidnplayr 363
        cmp     esi, -1
364
        jne     .find_last_entry
365
                                                                ; We found the last entry (pointer is now in edi)
366
                                                                ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
367
 
368
        pop     eax                                             ; pointer to packet
4052 hidnplayr 369
        mov     [edi + IPv4_FRAGMENT_entry.NextPtr], eax        ; update pointer of previous entry to the new entry
370
        mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
371
        mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], edi
372
        mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 373
 
374
        add     esp, 4
375
        ret
376
 
377
 
378
;------------------------------------
379
; We have received the first fragment
380
 
381
  .is_first_fragment:
3556 hidnplayr 382
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n"
3545 hidnplayr 383
                                                                ; try to locate a free slot..
4052 hidnplayr 384
        mov     ecx, IPv4_MAX_FRAGMENTS
385
        mov     esi, IPv4_FRAGMENT_LIST
3545 hidnplayr 386
  .find_free_slot:
4052 hidnplayr 387
        cmp     word [esi + IPv4_FRAGMENT_slot.ttl], 0
3545 hidnplayr 388
        je      .found_free_slot
4052 hidnplayr 389
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 390
        loop    .find_free_slot
391
        jmp     .dump                                           ; If no free slot was found, dump the packet
392
 
393
  .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
4052 hidnplayr 394
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
3545 hidnplayr 395
        mov     ax, [edx + IPv4_header.Identification]
4052 hidnplayr 396
        mov     [esi + IPv4_FRAGMENT_slot.id], ax
3545 hidnplayr 397
        mov     eax, [edx + IPv4_header.SourceAddress]
4052 hidnplayr 398
        mov     [esi + IPv4_FRAGMENT_slot.SrcIP], eax
3545 hidnplayr 399
        mov     eax, [edx + IPv4_header.DestinationAddress]
4052 hidnplayr 400
        mov     [esi + IPv4_FRAGMENT_slot.DstIP], eax
3545 hidnplayr 401
        pop     eax
4052 hidnplayr 402
        mov     [esi + IPv4_FRAGMENT_slot.ptr], eax
3545 hidnplayr 403
                                                                ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
4052 hidnplayr 404
        mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
405
        mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], -1
406
        mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 407
 
408
        add     esp, 4                                          ; balance stack and exit
409
        ret
410
 
411
 
412
;-----------------------------------
413
; We have received the last fragment
414
 
415
  .is_last_fragment:
3556 hidnplayr 416
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Last fragment packet received!\n"
3545 hidnplayr 417
 
418
        call    IPv4_find_fragment_slot
419
        cmp     esi, -1
420
        je      .dump
421
 
4052 hidnplayr 422
        mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]                     ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
3545 hidnplayr 423
        push    esi
424
        xor     eax, eax
425
        or      edi, -1
426
 
427
  .count_bytes:
4052 hidnplayr 428
        cmp     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
429
        jne     .destroy_slot_pop                                                       ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
430
        mov     cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]        ; Add total length
3545 hidnplayr 431
        xchg    cl, ch
3556 hidnplayr 432
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 433
        add     ax, cx
4052 hidnplayr 434
        movzx   cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]      ; Sub Header length
3545 hidnplayr 435
        and     cx, 0x000F
436
        shl     cx, 2
3556 hidnplayr 437
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
3545 hidnplayr 438
        sub     ax, cx
439
        mov     edi, esi
4052 hidnplayr 440
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3545 hidnplayr 441
        cmp     esi, -1
442
        jne     .count_bytes
443
 
444
        mov     esi, [esp+4]
4052 hidnplayr 445
        mov     [edi + IPv4_FRAGMENT_entry.NextPtr], esi                                ; Add this packet to the chain, this simplifies the following code
446
        mov     [esi + IPv4_FRAGMENT_entry.NextPtr], -1
447
        mov     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
448
        mov     [esi + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 449
 
4052 hidnplayr 450
        mov     cx, [edx + IPv4_header.TotalLength]                                     ; Note: This time we dont substract Header length
3545 hidnplayr 451
        xchg    cl, ch
3556 hidnplayr 452
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 453
        add     ax, cx
3556 hidnplayr 454
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
3545 hidnplayr 455
 
456
        push    eax
457
        mov     ax, [edx + IPv4_header.FlagsAndFragmentOffset]
458
        xchg    al, ah
459
        shl     ax, 3
460
        add     cx, ax
461
        pop     eax
3556 hidnplayr 462
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
3545 hidnplayr 463
 
464
        cmp     ax, cx
465
        jne     .destroy_slot_pop
466
 
467
        push    eax
468
        push    eax
469
        call    kernel_alloc
470
        test    eax, eax
471
        je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
472
        mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
473
 
474
  .rebuild_packet_loop:
4052 hidnplayr 475
        movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
3545 hidnplayr 476
        xchg    cl, ch                                                                  ;  intel byte order
477
        shl     cx, 3                                                                   ;   multiply by 8 and clear first 3 bits
3556 hidnplayr 478
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
3545 hidnplayr 479
 
480
        lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
4258 hidnplayr 481
        movzx   ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Find header size (in ebx) of fragment
3545 hidnplayr 482
        and     bx, 0x000F                                                              ;
483
        shl     bx, 2                                                                   ;
484
 
4258 hidnplayr 485
        lea     esi, [edx + sizeof.IPv4_FRAGMENT_entry]                                 ; Set esi to the correct begin of fragment
486
        movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]       ; Calculate total length of fragment
3545 hidnplayr 487
        xchg    cl, ch                                                                  ;  intel byte order
488
 
489
        cmp     edi, eax                                                                ; Is this packet the first fragment ?
490
        je      .first_fragment
491
        sub     cx, bx                                                                  ; If not, dont copy the header
492
        add     esi, ebx                                                                ;
493
  .first_fragment:
494
 
4258 hidnplayr 495
 
496
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
3545 hidnplayr 497
        push    cx                                                                      ; First copy dword-wise, then byte-wise
498
        shr     cx, 2                                                                   ;
3711 clevermous 499
        rep movsd                                                                       ;
3545 hidnplayr 500
        pop     cx                                                                      ;
501
        and     cx, 3                                                                   ;
3711 clevermous 502
        rep movsb                                                                       ;
3545 hidnplayr 503
 
504
        push    eax
4259 hidnplayr 505
        push    [edx + IPv4_FRAGMENT_entry.Owner]                                       ; we need to remeber the owner, in case this is the last packet
506
        push    [edx + IPv4_FRAGMENT_entry.NextPtr]                                     ; Set edx to the next pointer
3545 hidnplayr 507
        push    edx                                                                     ; Push pointer to fragment onto stack
4258 hidnplayr 508
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
3861 hidnplayr 509
        call    NET_packet_free                                                         ; free the previous fragment buffer (this uses the value from stack)
4258 hidnplayr 510
        pop     edx ebx eax
3545 hidnplayr 511
        cmp     edx, -1                                                                 ; Check if it is last fragment in chain
512
        jne     .rebuild_packet_loop
513
 
514
        pop     ecx
515
        xchg    cl, ch
516
        mov     edx, eax
517
        mov     [edx + IPv4_header.TotalLength], cx
4259 hidnplayr 518
        add     esp, 12
3545 hidnplayr 519
        xchg    cl, ch
4259 hidnplayr 520
        push    ecx edx                 ; size and pointer
521
        jmp     .handle_it              ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
3545 hidnplayr 522
 
523
  .destroy_slot_pop:
524
        add     esp, 4
525
  .destroy_slot:
3556 hidnplayr 526
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
3545 hidnplayr 527
        ; TODO!
528
        jmp     .dump
529
 
530
 
531
 
532
 
533
 
534
;-----------------------------------------------------------------
535
;
536
; find fragment slot
537
;
538
; IN: pointer to fragmented packet in edx
539
; OUT: pointer to slot in esi, -1 on error
540
;
541
;-----------------------------------------------------------------
542
align 4
543
IPv4_find_fragment_slot:
544
 
545
;;; TODO: the RFC says we should check protocol number too
546
 
547
        push    eax ebx ecx edx
548
        mov     ax, [edx + IPv4_header.Identification]
4052 hidnplayr 549
        mov     ecx, IPv4_MAX_FRAGMENTS
550
        mov     esi, IPv4_FRAGMENT_LIST
3545 hidnplayr 551
        mov     ebx, [edx + IPv4_header.SourceAddress]
552
        mov     edx, [edx + IPv4_header.DestinationAddress]
553
  .find_slot:
4052 hidnplayr 554
        cmp     [esi + IPv4_FRAGMENT_slot.id], ax
3545 hidnplayr 555
        jne     .try_next
4052 hidnplayr 556
        cmp     [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
3545 hidnplayr 557
        jne     .try_next
4052 hidnplayr 558
        cmp     [esi + IPv4_FRAGMENT_slot.DstIP], edx
3545 hidnplayr 559
        je      .found_slot
560
  .try_next:
4052 hidnplayr 561
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 562
        loop    .find_slot
563
 
564
        or      esi, -1
565
  .found_slot:
566
        pop     edx ecx ebx eax
567
        ret
568
 
569
 
570
;------------------------------------------------------------------
571
;
572
; IPv4_output
573
;
4052 hidnplayr 574
; IN:   eax = Destination IP
575
;       ecx = data length
576
;       edx = Source IP
5015 hidnplayr 577
;        di = TTL shl 8 + protocol
3545 hidnplayr 578
;
5015 hidnplayr 579
; OUT:  eax = pointer to buffer start / 0 on error
580
;       ebx = device ptr (send packet through this device)
581
;       ecx = data length
582
;       edx = size of complete frame
583
;       edi = start of IPv4 payload
3545 hidnplayr 584
;
585
;------------------------------------------------------------------
586
align 4
587
IPv4_output:
588
 
3601 hidnplayr 589
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, eax
3545 hidnplayr 590
 
591
        cmp     ecx, 65500              ; Max IPv4 packet size
592
        ja      .too_large
593
 
4052 hidnplayr 594
        push    ecx di eax
595
        call    IPv4_route              ; outputs device number in edi, dest ip in eax, source IP in edx
596
        push    edx
3610 hidnplayr 597
        test    edi, edi
598
        jz      .loopback
599
 
3545 hidnplayr 600
        call    ARP_IP_to_MAC
601
        test    eax, 0xffff0000         ; error bits
602
        jnz     .arp_error
603
        push    ebx                     ; push the mac onto the stack
604
        push    ax
605
 
4052 hidnplayr 606
        inc     [IPv4_packets_tx + edi]   ; update stats
3545 hidnplayr 607
 
5015 hidnplayr 608
        mov     ax, ETHER_PROTO_IPv4
3638 hidnplayr 609
        mov     ebx, [NET_DRV_LIST + edi]
4052 hidnplayr 610
        mov     ecx, [esp + 6 + 8 + 2]
3545 hidnplayr 611
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 612
        mov     edx, esp
3545 hidnplayr 613
        call    ETH_output
614
        jz      .eth_error
615
        add     esp, 6                  ; pop the mac out of the stack
616
 
617
  .continue:
618
        xchg    cl, ch                                  ; internet byte order
619
        mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
620
        mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
621
        mov     [edi + IPv4_header.TotalLength], cx
622
        mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
623
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
4052 hidnplayr 624
 
3545 hidnplayr 625
        mov     [edi + IPv4_header.HeaderChecksum], 0
626
        popd    [edi + IPv4_header.SourceAddress]
627
        popd    [edi + IPv4_header.DestinationAddress]
628
 
4052 hidnplayr 629
        pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
630
;               [edi + IPv4_header.Protocol]
631
 
3545 hidnplayr 632
        pop     ecx
633
 
634
        IPv4_checksum edi
635
        add     edi, sizeof.IPv4_header
3556 hidnplayr 636
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
3545 hidnplayr 637
        ret
638
 
639
  .eth_error:
3603 hidnplayr 640
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
3545 hidnplayr 641
        add     esp, 3*4+2+6
5015 hidnplayr 642
        xor     eax, eax
3545 hidnplayr 643
        ret
644
 
645
  .arp_error:
3603 hidnplayr 646
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
3545 hidnplayr 647
        add     esp, 3*4+2
5015 hidnplayr 648
        xor     eax, eax
3545 hidnplayr 649
        ret
650
 
651
  .too_large:
3556 hidnplayr 652
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
5015 hidnplayr 653
        xor     eax, eax
3545 hidnplayr 654
        ret
655
 
656
  .loopback:
3610 hidnplayr 657
        mov     dword [esp + 2], eax            ; change source IP to dest IP
658
        mov     ecx, [esp + 10]
3545 hidnplayr 659
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 660
        mov     edi, AF_INET4
3545 hidnplayr 661
        call    LOOP_output
662
        jmp     .continue
663
 
664
 
665
 
666
 
667
;------------------------------------------------------------------
668
;
669
; IPv4_output_raw
670
;
671
; IN: eax = socket ptr
672
;     ecx = data length
673
;     esi = data ptr
674
;
5015 hidnplayr 675
; OUT: eax = -1 on error
3545 hidnplayr 676
;
677
;------------------------------------------------------------------
678
align 4
679
IPv4_output_raw:
680
 
681
        DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
682
 
683
        cmp     ecx, 1480               ;;;;; FIXME
684
        ja      .too_large
685
 
686
        sub     esp, 8
687
        push    esi eax
688
 
689
        call    IPv4_route
690
        call    ARP_IP_to_MAC
691
 
692
        test    eax, 0xffff0000         ; error bits
693
        jnz     .arp_error
694
 
695
        push    ebx                     ; push the mac
696
        push    ax
697
 
4052 hidnplayr 698
        inc     [IPv4_packets_tx + 4*edi]
5015 hidnplayr 699
        mov     ax, ETHER_PROTO_IPv4
3601 hidnplayr 700
        mov     ebx, [NET_DRV_LIST + 4*edi]
3545 hidnplayr 701
        mov     ecx, [esp + 6 + 4]
702
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 703
        mov     edx, esp
3545 hidnplayr 704
        call    ETH_output
705
        jz      .error
706
        add     esp, 6  ; pop the mac
707
 
708
        mov     dword[esp+4+4], edx
709
        mov     dword[esp+4+4+4], eax
710
 
711
        pop     eax esi
712
;; todo: check socket options if we should add header, or just compute checksum
713
 
714
        push    edi ecx
3711 clevermous 715
        rep movsb
3545 hidnplayr 716
        pop     ecx edi
717
 
718
;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
719
;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
720
;        [edi + IPv4_header.TotalLength]
721
;        [edi + IPv4_header.TotalLength]                ; internet byte order
722
;        [edi + IPv4_header.FlagsAndFragmentOffset]
723
 
724
        mov     [edi + IPv4_header.HeaderChecksum], 0
725
 
726
;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
727
;        [edi + IPv4_header.Protocol]
728
;        [edi + IPv4_header.Identification]             ; fragment id
729
;        [edi + IPv4_header.SourceAddress]
730
;        [edi + IPv4_header.DestinationAddress]
731
 
732
        IPv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
733
        add     edi, sizeof.IPv4_header
3556 hidnplayr 734
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
3545 hidnplayr 735
        call    [ebx + NET_DEVICE.transmit]
736
        ret
737
 
738
  .error:
739
        add     esp, 6
740
  .arp_error:
741
        add     esp, 8+4+4
742
  .too_large:
3556 hidnplayr 743
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output_raw: Failed\n"
5015 hidnplayr 744
        or      eax, -1
3545 hidnplayr 745
        ret
746
 
747
 
748
;--------------------------------------------------------
749
;
750
;
751
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
752
;     dword [esp+4] = buffer size
753
;     esi = pointer to ip header in that buffer
754
;     ecx = max size of fragments
755
;
756
; OUT: /
757
;
758
;--------------------------------------------------------
759
 
760
align 4
761
IPv4_fragment:
762
 
3556 hidnplayr 763
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
3545 hidnplayr 764
 
765
        and     ecx, not 111b   ; align 4
766
 
767
        cmp     ecx, sizeof.IPv4_header + 8     ; must be able to put at least 8 bytes
768
        jb      .err2
769
 
770
        push    esi ecx
771
        mov     eax, [esi + IPv4_header.DestinationAddress]
772
        call    ARP_IP_to_MAC
773
        pop     ecx esi
774
        cmp     eax, -1
775
        jz      .err2
776
 
777
        push    ebx
778
        push    ax
779
 
780
        mov     ebx, [NET_DRV_LIST]
781
        lea     eax, [ebx + ETH_DEVICE.mac]
782
        push    eax
783
 
784
 
785
        push    esi                             ; ptr to ip header
786
        sub     ecx, sizeof.IPv4_header         ; substract header size
787
        push    ecx                             ; max data size
788
        push    dword 0                         ; offset
789
 
790
  .new_fragment:
3556 hidnplayr 791
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
3545 hidnplayr 792
 
5015 hidnplayr 793
        mov     ax, ETHER_PROTO_IPv4
3545 hidnplayr 794
        lea     ebx, [esp + 4*4]
795
        call    ETH_output
796
        jz      .err
797
 
798
; copy header
799
        mov     esi, [esp + 2*4]
800
        mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
3711 clevermous 801
        rep movsd
3545 hidnplayr 802
 
803
; copy data
804
        mov     esi, [esp + 2*4]
805
        add     esi, sizeof.IPv4_header
806
        add     esi, [esp]      ; offset
807
 
808
        mov     ecx, [esp + 1*4]
3556 hidnplayr 809
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment: copying %u bytes\n", ecx
3711 clevermous 810
        rep movsb
3545 hidnplayr 811
 
812
; now, correct header
813
        mov     ecx, [esp + 1*4]
814
        add     ecx, sizeof.IPv4_header
815
        xchg    cl, ch
816
        mov     [edi + IPv4_header.TotalLength], cx
817
 
818
        mov     ecx, [esp]              ; offset
819
        xchg    cl, ch
820
 
821
;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
822
;        je      .last_fragment
823
        or      cx, 1 shl 2             ; more fragments
824
;  .last_fragment:
825
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], cx
826
 
827
        mov     [edi + IPv4_header.HeaderChecksum], 0
828
 
829
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
830
        mov     ecx, [esp + 1*4]
831
 
832
        push    edx eax
833
        IPv4_checksum edi
834
 
835
        call    [ebx + NET_DEVICE.transmit]
836
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
837
 
3711 clevermous 838
        mov     ecx, [esp+4]
3545 hidnplayr 839
        add     [esp], ecx
840
 
841
        mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
842
        add     ecx, [esp+3*4+6+4+4]    ; buff size
843
        sub     ecx, [esp+2*4]          ; ptr to ip header
844
        add     ecx, [esp]              ; offset
845
 
3556 hidnplayr 846
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: %u bytes remaining\n", ecx
3545 hidnplayr 847
 
848
        cmp     ecx, [esp+1*4]
849
        jae     .new_fragment
850
 
851
        mov     [esp+4], ecx            ; set fragment size to remaining packet size
852
        jmp     .new_fragment
853
 
854
      .err:
3556 hidnplayr 855
        DEBUGF  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
3545 hidnplayr 856
      .done:
857
        add     esp, 12 + 4 + 6
858
      .err2:
3556 hidnplayr 859
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: dumping\n"
3861 hidnplayr 860
        call    NET_packet_free
3545 hidnplayr 861
        add     esp, 4
862
 
863
        ret
864
 
865
 
866
 
867
;---------------------------------------------------------------------------
868
;
869
; IPv4_route
870
;
871
; IN:   eax = Destination IP
4052 hidnplayr 872
;       edx = Source IP
873
; OUT:  eax = Destination IP (or gateway IP)
874
;       edx = Source IP
875
;       edi = device number*4
876
; DESTROYED:
877
;       ecx
3545 hidnplayr 878
;
879
;---------------------------------------------------------------------------
880
align 4
4052 hidnplayr 881
IPv4_route:     ; TODO: return error if no valid route found
3545 hidnplayr 882
 
883
        cmp     eax, 0xffffffff
884
        je      .broadcast
885
 
886
        xor     edi, edi
887
  .loop:
4052 hidnplayr 888
        mov     ebx, [IP_LIST + edi]
889
        and     ebx, [SUBNET_LIST + edi]
3545 hidnplayr 890
        jz      .next
4052 hidnplayr 891
        mov     ecx, eax
892
        and     ecx, [SUBNET_LIST + edi]
893
        cmp     ebx, ecx
894
        je      .got_it
3545 hidnplayr 895
  .next:
896
        add     edi, 4
4052 hidnplayr 897
        cmp     edi, 4*NET_DEVICES_MAX
898
        jb      .loop
3545 hidnplayr 899
 
4052 hidnplayr 900
        mov     eax, [GATEWAY_LIST + 4]         ; TODO: let user (or a user space daemon) configure default route
3545 hidnplayr 901
  .broadcast:
4052 hidnplayr 902
        mov     edi, 4                          ; TODO: same as above
903
  .got_it:
904
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
905
        test    edx, edx
906
        jnz     @f
907
        mov     edx, [IP_LIST + edi]
908
  @@:
909
 
3545 hidnplayr 910
        ret
911
 
912
 
913
 
914
;---------------------------------------------------------------------------
915
;
916
; IPv4_get_frgmnt_num
917
;
918
; IN: /
919
; OUT: fragment number in ax
920
;
921
;---------------------------------------------------------------------------
922
align 4
923
IPv4_get_frgmnt_num:
924
        xor     ax, ax  ;;; TODO: replace this with real code
925
 
926
        ret
927
 
928
 
4030 hidnplayr 929
;-----------------------------------------------------------------
930
;
931
; IPv4_connect
932
;
933
;   IN: eax = socket pointer
934
;  OUT: eax = 0 ok / -1 error
935
;       ebx = error code
936
;
937
;-------------------------
938
align 4
939
IPv4_connect:
940
 
4035 hidnplayr 941
        push    eax edx
4030 hidnplayr 942
        lea     ecx, [eax + SOCKET.mutex]
943
        call    mutex_lock
4035 hidnplayr 944
        pop     edx eax
4030 hidnplayr 945
 
946
; Fill in local IP
947
        cmp     [eax + IP_SOCKET.LocalIP], 0
948
        jne     @f
949
        push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
950
        pop     [eax + IP_SOCKET.LocalIP]
951
 
952
; Fill in remote IP
953
        pushd   [edx + 4]
954
        pop     [eax + IP_SOCKET.RemoteIP]
955
 
4035 hidnplayr 956
; Set up data receiving queue
4030 hidnplayr 957
        push    eax
4035 hidnplayr 958
        init_queue (eax + SOCKET_QUEUE_LOCATION)
4030 hidnplayr 959
        pop     eax
960
 
961
        lea     ecx, [eax + SOCKET.mutex]
962
        call    mutex_unlock
963
 
964
        xor     eax, eax
965
        ret
966
 
967
 
3545 hidnplayr 968
;---------------------------------------------------------------------------
969
;
970
; IPv4_API
971
;
972
; This function is called by system function 75
973
;
974
; IN:  subfunction number in bl
975
;      device number in bh
976
;      ecx, edx, .. depends on subfunction
977
;
978
; OUT:
979
;
980
;---------------------------------------------------------------------------
981
align 4
982
IPv4_api:
983
 
984
        movzx   eax, bh
985
        shl     eax, 2
986
 
987
        and     ebx, 0x000000ff
988
        cmp     ebx, .number
989
        ja      .error
990
        jmp     dword [.table + 4*ebx]
991
 
992
  .table:
993
        dd      .packets_tx     ; 0
994
        dd      .packets_rx     ; 1
995
        dd      .read_ip        ; 2
996
        dd      .write_ip       ; 3
997
        dd      .read_dns       ; 4
998
        dd      .write_dns      ; 5
999
        dd      .read_subnet    ; 6
1000
        dd      .write_subnet   ; 7
1001
        dd      .read_gateway   ; 8
1002
        dd      .write_gateway  ; 9
1003
  .number = ($ - .table) / 4 - 1
1004
 
1005
  .error:
1006
        mov     eax, -1
1007
        ret
1008
 
1009
  .packets_tx:
4052 hidnplayr 1010
        mov     eax, [IPv4_packets_tx + eax]
3545 hidnplayr 1011
        ret
1012
 
1013
  .packets_rx:
4052 hidnplayr 1014
        mov     eax, [IPv4_packets_rx + eax]
3545 hidnplayr 1015
        ret
1016
 
1017
  .read_ip:
1018
        mov     eax, [IP_LIST + eax]
1019
        ret
1020
 
1021
  .write_ip:
1022
        mov     [IP_LIST + eax], ecx
1023
        mov     edi, eax                        ; device number, we'll need it for ARP
1024
 
1025
        ; pre-calculate the local broadcast address
1026
        mov     ebx, [SUBNET_LIST + eax]
1027
        not     ebx
1028
        or      ebx, ecx
1029
        mov     [BROADCAST_LIST + eax], ebx
1030
 
3601 hidnplayr 1031
        mov     ebx, [NET_DRV_LIST + eax]
1032
        mov     eax, [IP_LIST + eax]
3545 hidnplayr 1033
        call    ARP_output_request              ; now send a gratuitous ARP
1034
 
1035
        call    NET_send_event
1036
        xor     eax, eax
1037
        ret
1038
 
1039
  .read_dns:
1040
        mov     eax, [DNS_LIST + eax]
1041
        ret
1042
 
1043
  .write_dns:
1044
        mov     [DNS_LIST + eax], ecx
1045
        call    NET_send_event
1046
        xor     eax, eax
1047
        ret
1048
 
1049
  .read_subnet:
1050
        mov     eax, [SUBNET_LIST + eax]
1051
        ret
1052
 
1053
  .write_subnet:
1054
        mov     [SUBNET_LIST + eax], ecx
1055
 
1056
        ; pre-calculate the local broadcast address
1057
        mov     ebx, [IP_LIST + eax]
1058
        not     ecx
1059
        or      ecx, ebx
1060
        mov     [BROADCAST_LIST + eax], ecx
1061
 
1062
        call    NET_send_event
1063
        xor     eax, eax
1064
        ret
1065
 
1066
  .read_gateway:
1067
        mov     eax, [GATEWAY_LIST + eax]
1068
        ret
1069
 
1070
  .write_gateway:
1071
        mov     [GATEWAY_LIST + eax], ecx
1072
 
1073
        call    NET_send_event
1074
        xor     eax, eax
1075
        ret