Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3861 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2013. 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: 4976 $
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
577
;       di  = TTL shl 8 + protocol
3545 hidnplayr 578
;
4052 hidnplayr 579
; OUT:  eax = pointer to buffer start
580
;       ebx = pointer to device struct (needed for sending procedure)
581
;       ecx = unchanged (packet size of embedded data)
582
;       edx = size of complete buffer
583
;       edi = pointer to start of data (0 on error)
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
3545 hidnplayr 597
 
3610 hidnplayr 598
        test    edi, edi
599
        jz      .loopback
600
 
3545 hidnplayr 601
        call    ARP_IP_to_MAC
602
        test    eax, 0xffff0000         ; error bits
603
        jnz     .arp_error
604
        push    ebx                     ; push the mac onto the stack
605
        push    ax
606
 
4052 hidnplayr 607
        inc     [IPv4_packets_tx + edi]   ; update stats
3545 hidnplayr 608
 
3638 hidnplayr 609
        mov     ebx, [NET_DRV_LIST + edi]
3545 hidnplayr 610
        lea     eax, [ebx + ETH_DEVICE.mac]
611
        mov     edx, esp
4052 hidnplayr 612
        mov     ecx, [esp + 6 + 8 + 2]
3545 hidnplayr 613
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 614
        mov     di, ETHER_PROTO_IPv4
3545 hidnplayr 615
        call    ETH_output
616
        jz      .eth_error
617
        add     esp, 6                  ; pop the mac out of the stack
618
 
619
  .continue:
620
        xchg    cl, ch                                  ; internet byte order
621
        mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
622
        mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
623
        mov     [edi + IPv4_header.TotalLength], cx
624
        mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
625
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
4052 hidnplayr 626
 
3545 hidnplayr 627
        mov     [edi + IPv4_header.HeaderChecksum], 0
628
        popd    [edi + IPv4_header.SourceAddress]
629
        popd    [edi + IPv4_header.DestinationAddress]
630
 
4052 hidnplayr 631
        pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
632
;               [edi + IPv4_header.Protocol]
633
 
3545 hidnplayr 634
        pop     ecx
635
 
636
        IPv4_checksum edi
637
        add     edi, sizeof.IPv4_header
3556 hidnplayr 638
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
3545 hidnplayr 639
        ret
640
 
641
  .eth_error:
3603 hidnplayr 642
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
3545 hidnplayr 643
        add     esp, 3*4+2+6
644
        xor     edi, edi
645
        ret
646
 
647
  .arp_error:
3603 hidnplayr 648
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
3545 hidnplayr 649
        add     esp, 3*4+2
650
        xor     edi, edi
651
        ret
652
 
653
  .too_large:
3556 hidnplayr 654
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
3545 hidnplayr 655
        xor     edi, edi
656
        ret
657
 
658
  .loopback:
3610 hidnplayr 659
        mov     dword [esp + 2], eax            ; change source IP to dest IP
660
        mov     ecx, [esp + 10]
3545 hidnplayr 661
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 662
        mov     edi, AF_INET4
3545 hidnplayr 663
        call    LOOP_output
664
        jmp     .continue
665
 
666
 
667
 
668
 
669
;------------------------------------------------------------------
670
;
671
; IPv4_output_raw
672
;
673
; IN: eax = socket ptr
674
;     ecx = data length
675
;     esi = data ptr
676
;
677
; OUT: /
678
;
679
;------------------------------------------------------------------
680
align 4
681
IPv4_output_raw:
682
 
683
        DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
684
 
685
        cmp     ecx, 1480               ;;;;; FIXME
686
        ja      .too_large
687
 
688
        sub     esp, 8
689
        push    esi eax
690
 
691
        call    IPv4_route
692
        call    ARP_IP_to_MAC
693
 
694
        test    eax, 0xffff0000         ; error bits
695
        jnz     .arp_error
696
 
697
        push    ebx                     ; push the mac
698
        push    ax
699
 
4052 hidnplayr 700
        inc     [IPv4_packets_tx + 4*edi]
3601 hidnplayr 701
        mov     ebx, [NET_DRV_LIST + 4*edi]
3545 hidnplayr 702
        lea     eax, [ebx + ETH_DEVICE.mac]
703
        mov     edx, esp
704
        mov     ecx, [esp + 6 + 4]
705
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 706
        mov     di, ETHER_PROTO_IPv4
3545 hidnplayr 707
        call    ETH_output
708
        jz      .error
709
 
710
        add     esp, 6  ; pop the mac
711
 
712
        mov     dword[esp+4+4], edx
713
        mov     dword[esp+4+4+4], eax
714
 
715
        pop     eax esi
716
;; todo: check socket options if we should add header, or just compute checksum
717
 
718
        push    edi ecx
3711 clevermous 719
        rep movsb
3545 hidnplayr 720
        pop     ecx edi
721
 
722
;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
723
;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
724
;        [edi + IPv4_header.TotalLength]
725
;        [edi + IPv4_header.TotalLength]                ; internet byte order
726
;        [edi + IPv4_header.FlagsAndFragmentOffset]
727
 
728
        mov     [edi + IPv4_header.HeaderChecksum], 0
729
 
730
;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
731
;        [edi + IPv4_header.Protocol]
732
;        [edi + IPv4_header.Identification]             ; fragment id
733
;        [edi + IPv4_header.SourceAddress]
734
;        [edi + IPv4_header.DestinationAddress]
735
 
736
        IPv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
737
        add     edi, sizeof.IPv4_header
3556 hidnplayr 738
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
3545 hidnplayr 739
        call    [ebx + NET_DEVICE.transmit]
740
        ret
741
 
742
  .error:
743
        add     esp, 6
744
  .arp_error:
745
        add     esp, 8+4+4
746
  .too_large:
3556 hidnplayr 747
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output_raw: Failed\n"
3545 hidnplayr 748
        sub     edi, edi
749
        ret
750
 
751
 
752
;--------------------------------------------------------
753
;
754
;
755
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
756
;     dword [esp+4] = buffer size
757
;     esi = pointer to ip header in that buffer
758
;     ecx = max size of fragments
759
;
760
; OUT: /
761
;
762
;--------------------------------------------------------
763
 
764
align 4
765
IPv4_fragment:
766
 
3556 hidnplayr 767
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
3545 hidnplayr 768
 
769
        and     ecx, not 111b   ; align 4
770
 
771
        cmp     ecx, sizeof.IPv4_header + 8     ; must be able to put at least 8 bytes
772
        jb      .err2
773
 
774
        push    esi ecx
775
        mov     eax, [esi + IPv4_header.DestinationAddress]
776
        call    ARP_IP_to_MAC
777
        pop     ecx esi
778
        cmp     eax, -1
779
        jz      .err2
780
 
781
        push    ebx
782
        push    ax
783
 
784
        mov     ebx, [NET_DRV_LIST]
785
        lea     eax, [ebx + ETH_DEVICE.mac]
786
        push    eax
787
 
788
 
789
        push    esi                             ; ptr to ip header
790
        sub     ecx, sizeof.IPv4_header         ; substract header size
791
        push    ecx                             ; max data size
792
        push    dword 0                         ; offset
793
 
794
  .new_fragment:
3556 hidnplayr 795
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
3545 hidnplayr 796
 
797
 
798
        mov     eax, [esp + 3*4]
799
        lea     ebx, [esp + 4*4]
3600 hidnplayr 800
        mov     di , ETHER_PROTO_IPv4
3545 hidnplayr 801
        call    ETH_output
802
 
803
        cmp     edi, -1
804
        jz      .err
805
 
806
; copy header
807
        mov     esi, [esp + 2*4]
808
        mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
3711 clevermous 809
        rep movsd
3545 hidnplayr 810
 
811
; copy data
812
        mov     esi, [esp + 2*4]
813
        add     esi, sizeof.IPv4_header
814
        add     esi, [esp]      ; offset
815
 
816
        mov     ecx, [esp + 1*4]
3556 hidnplayr 817
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment: copying %u bytes\n", ecx
3711 clevermous 818
        rep movsb
3545 hidnplayr 819
 
820
; now, correct header
821
        mov     ecx, [esp + 1*4]
822
        add     ecx, sizeof.IPv4_header
823
        xchg    cl, ch
824
        mov     [edi + IPv4_header.TotalLength], cx
825
 
826
        mov     ecx, [esp]              ; offset
827
        xchg    cl, ch
828
 
829
;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
830
;        je      .last_fragment
831
        or      cx, 1 shl 2             ; more fragments
832
;  .last_fragment:
833
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], cx
834
 
835
        mov     [edi + IPv4_header.HeaderChecksum], 0
836
 
837
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
838
        mov     ecx, [esp + 1*4]
839
 
840
        push    edx eax
841
        IPv4_checksum edi
842
 
843
        call    [ebx + NET_DEVICE.transmit]
844
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
845
 
3711 clevermous 846
        mov     ecx, [esp+4]
3545 hidnplayr 847
        add     [esp], ecx
848
 
849
        mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
850
        add     ecx, [esp+3*4+6+4+4]    ; buff size
851
        sub     ecx, [esp+2*4]          ; ptr to ip header
852
        add     ecx, [esp]              ; offset
853
 
3556 hidnplayr 854
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: %u bytes remaining\n", ecx
3545 hidnplayr 855
 
856
        cmp     ecx, [esp+1*4]
857
        jae     .new_fragment
858
 
859
        mov     [esp+4], ecx            ; set fragment size to remaining packet size
860
        jmp     .new_fragment
861
 
862
      .err:
3556 hidnplayr 863
        DEBUGF  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
3545 hidnplayr 864
      .done:
865
        add     esp, 12 + 4 + 6
866
      .err2:
3556 hidnplayr 867
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: dumping\n"
3861 hidnplayr 868
        call    NET_packet_free
3545 hidnplayr 869
        add     esp, 4
870
 
871
        ret
872
 
873
 
874
 
875
;---------------------------------------------------------------------------
876
;
877
; IPv4_route
878
;
879
; IN:   eax = Destination IP
4052 hidnplayr 880
;       edx = Source IP
881
; OUT:  eax = Destination IP (or gateway IP)
882
;       edx = Source IP
883
;       edi = device number*4
884
; DESTROYED:
885
;       ecx
3545 hidnplayr 886
;
887
;---------------------------------------------------------------------------
888
align 4
4052 hidnplayr 889
IPv4_route:     ; TODO: return error if no valid route found
3545 hidnplayr 890
 
891
        cmp     eax, 0xffffffff
892
        je      .broadcast
893
 
894
        xor     edi, edi
895
  .loop:
4052 hidnplayr 896
        mov     ebx, [IP_LIST + edi]
897
        and     ebx, [SUBNET_LIST + edi]
3545 hidnplayr 898
        jz      .next
4052 hidnplayr 899
        mov     ecx, eax
900
        and     ecx, [SUBNET_LIST + edi]
901
        cmp     ebx, ecx
902
        je      .got_it
3545 hidnplayr 903
  .next:
904
        add     edi, 4
4052 hidnplayr 905
        cmp     edi, 4*NET_DEVICES_MAX
906
        jb      .loop
3545 hidnplayr 907
 
4052 hidnplayr 908
        mov     eax, [GATEWAY_LIST + 4]         ; TODO: let user (or a user space daemon) configure default route
3545 hidnplayr 909
  .broadcast:
4052 hidnplayr 910
        mov     edi, 4                          ; TODO: same as above
911
  .got_it:
912
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
913
        test    edx, edx
914
        jnz     @f
915
        mov     edx, [IP_LIST + edi]
916
  @@:
917
 
3545 hidnplayr 918
        ret
919
 
920
 
921
 
922
;---------------------------------------------------------------------------
923
;
924
; IPv4_get_frgmnt_num
925
;
926
; IN: /
927
; OUT: fragment number in ax
928
;
929
;---------------------------------------------------------------------------
930
align 4
931
IPv4_get_frgmnt_num:
932
        xor     ax, ax  ;;; TODO: replace this with real code
933
 
934
        ret
935
 
936
 
4030 hidnplayr 937
;-----------------------------------------------------------------
938
;
939
; IPv4_connect
940
;
941
;   IN: eax = socket pointer
942
;  OUT: eax = 0 ok / -1 error
943
;       ebx = error code
944
;
945
;-------------------------
946
align 4
947
IPv4_connect:
948
 
4035 hidnplayr 949
        push    eax edx
4030 hidnplayr 950
        lea     ecx, [eax + SOCKET.mutex]
951
        call    mutex_lock
4035 hidnplayr 952
        pop     edx eax
4030 hidnplayr 953
 
954
; Fill in local IP
955
        cmp     [eax + IP_SOCKET.LocalIP], 0
956
        jne     @f
957
        push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
958
        pop     [eax + IP_SOCKET.LocalIP]
959
 
960
; Fill in remote IP
961
        pushd   [edx + 4]
962
        pop     [eax + IP_SOCKET.RemoteIP]
963
 
4035 hidnplayr 964
; Set up data receiving queue
4030 hidnplayr 965
        push    eax
4035 hidnplayr 966
        init_queue (eax + SOCKET_QUEUE_LOCATION)
4030 hidnplayr 967
        pop     eax
968
 
969
        lea     ecx, [eax + SOCKET.mutex]
970
        call    mutex_unlock
971
 
972
        xor     eax, eax
973
        ret
974
 
975
 
3545 hidnplayr 976
;---------------------------------------------------------------------------
977
;
978
; IPv4_API
979
;
980
; This function is called by system function 75
981
;
982
; IN:  subfunction number in bl
983
;      device number in bh
984
;      ecx, edx, .. depends on subfunction
985
;
986
; OUT:
987
;
988
;---------------------------------------------------------------------------
989
align 4
990
IPv4_api:
991
 
992
        movzx   eax, bh
993
        shl     eax, 2
994
 
995
        and     ebx, 0x000000ff
996
        cmp     ebx, .number
997
        ja      .error
998
        jmp     dword [.table + 4*ebx]
999
 
1000
  .table:
1001
        dd      .packets_tx     ; 0
1002
        dd      .packets_rx     ; 1
1003
        dd      .read_ip        ; 2
1004
        dd      .write_ip       ; 3
1005
        dd      .read_dns       ; 4
1006
        dd      .write_dns      ; 5
1007
        dd      .read_subnet    ; 6
1008
        dd      .write_subnet   ; 7
1009
        dd      .read_gateway   ; 8
1010
        dd      .write_gateway  ; 9
1011
  .number = ($ - .table) / 4 - 1
1012
 
1013
  .error:
1014
        mov     eax, -1
1015
        ret
1016
 
1017
  .packets_tx:
4052 hidnplayr 1018
        mov     eax, [IPv4_packets_tx + eax]
3545 hidnplayr 1019
        ret
1020
 
1021
  .packets_rx:
4052 hidnplayr 1022
        mov     eax, [IPv4_packets_rx + eax]
3545 hidnplayr 1023
        ret
1024
 
1025
  .read_ip:
1026
        mov     eax, [IP_LIST + eax]
1027
        ret
1028
 
1029
  .write_ip:
1030
        mov     [IP_LIST + eax], ecx
1031
        mov     edi, eax                        ; device number, we'll need it for ARP
1032
 
1033
        ; pre-calculate the local broadcast address
1034
        mov     ebx, [SUBNET_LIST + eax]
1035
        not     ebx
1036
        or      ebx, ecx
1037
        mov     [BROADCAST_LIST + eax], ebx
1038
 
3601 hidnplayr 1039
        mov     ebx, [NET_DRV_LIST + eax]
1040
        mov     eax, [IP_LIST + eax]
3545 hidnplayr 1041
        call    ARP_output_request              ; now send a gratuitous ARP
1042
 
1043
        call    NET_send_event
1044
        xor     eax, eax
1045
        ret
1046
 
1047
  .read_dns:
1048
        mov     eax, [DNS_LIST + eax]
1049
        ret
1050
 
1051
  .write_dns:
1052
        mov     [DNS_LIST + eax], ecx
1053
        call    NET_send_event
1054
        xor     eax, eax
1055
        ret
1056
 
1057
  .read_subnet:
1058
        mov     eax, [SUBNET_LIST + eax]
1059
        ret
1060
 
1061
  .write_subnet:
1062
        mov     [SUBNET_LIST + eax], ecx
1063
 
1064
        ; pre-calculate the local broadcast address
1065
        mov     ebx, [IP_LIST + eax]
1066
        not     ecx
1067
        or      ecx, ebx
1068
        mov     [BROADCAST_LIST + eax], ecx
1069
 
1070
        call    NET_send_event
1071
        xor     eax, eax
1072
        ret
1073
 
1074
  .read_gateway:
1075
        mov     eax, [GATEWAY_LIST + eax]
1076
        ret
1077
 
1078
  .write_gateway:
1079
        mov     [GATEWAY_LIST + eax], ecx
1080
 
1081
        call    NET_send_event
1082
        xor     eax, eax
1083
        ret