Subversion Repositories Kolibri OS

Rev

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

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