Subversion Repositories Kolibri OS

Rev

Rev 5522 | Rev 5842 | 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: 5584 $
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
 
5522 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
5522 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
5522 hidnplayr 326
        call    NET_BUFF_free
3545 hidnplayr 327
        ret
328
 
329
 
330
;---------------------------
331
; Fragmented packet handler
332
 
333
 
334
  .has_fragments:
335
        movzx   eax, [edx + IPv4_header.FlagsAndFragmentOffset]
336
        xchg    al, ah
337
        shl     ax, 3
338
 
4258 hidnplayr 339
        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 340
 
341
        test    ax, ax                                          ; Is this the first packet of the fragment?
342
        jz      .is_first_fragment
343
 
344
 
345
;-------------------------------------------------------
346
; We have a fragmented IP packet, but it's not the first
347
 
3556 hidnplayr 348
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Middle fragment packet received!\n"
3545 hidnplayr 349
 
350
        call    IPv4_find_fragment_slot
351
        cmp     esi, -1
352
        je      .dump
353
 
4052 hidnplayr 354
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; Reset the ttl
355
        mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]
3545 hidnplayr 356
        or      edi, -1
357
  .find_last_entry:                                             ; The following routine will try to find the last entry
4052 hidnplayr 358
        cmp     edi, [esi + IPv4_FRAGMENT_entry.PrevPtr]
3545 hidnplayr 359
        jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
360
        mov     edi, esi
4052 hidnplayr 361
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3545 hidnplayr 362
        cmp     esi, -1
363
        jne     .find_last_entry
364
                                                                ; We found the last entry (pointer is now in edi)
365
                                                                ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
366
 
367
        pop     eax                                             ; pointer to packet
4052 hidnplayr 368
        mov     [edi + IPv4_FRAGMENT_entry.NextPtr], eax        ; update pointer of previous entry to the new entry
369
        mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
370
        mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], edi
371
        mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 372
 
373
        ret
374
 
375
 
376
;------------------------------------
377
; We have received the first fragment
378
 
379
  .is_first_fragment:
3556 hidnplayr 380
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n"
3545 hidnplayr 381
                                                                ; try to locate a free slot..
4052 hidnplayr 382
        mov     ecx, IPv4_MAX_FRAGMENTS
383
        mov     esi, IPv4_FRAGMENT_LIST
3545 hidnplayr 384
  .find_free_slot:
4052 hidnplayr 385
        cmp     word [esi + IPv4_FRAGMENT_slot.ttl], 0
3545 hidnplayr 386
        je      .found_free_slot
4052 hidnplayr 387
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 388
        loop    .find_free_slot
389
        jmp     .dump                                           ; If no free slot was found, dump the packet
390
 
391
  .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
4052 hidnplayr 392
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
3545 hidnplayr 393
        mov     ax, [edx + IPv4_header.Identification]
4052 hidnplayr 394
        mov     [esi + IPv4_FRAGMENT_slot.id], ax
3545 hidnplayr 395
        mov     eax, [edx + IPv4_header.SourceAddress]
4052 hidnplayr 396
        mov     [esi + IPv4_FRAGMENT_slot.SrcIP], eax
3545 hidnplayr 397
        mov     eax, [edx + IPv4_header.DestinationAddress]
4052 hidnplayr 398
        mov     [esi + IPv4_FRAGMENT_slot.DstIP], eax
3545 hidnplayr 399
        pop     eax
4052 hidnplayr 400
        mov     [esi + IPv4_FRAGMENT_slot.ptr], eax
3545 hidnplayr 401
                                                                ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
4052 hidnplayr 402
        mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
403
        mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], -1
404
        mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 405
 
406
        ret
407
 
408
 
409
;-----------------------------------
410
; We have received the last fragment
411
 
412
  .is_last_fragment:
3556 hidnplayr 413
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Last fragment packet received!\n"
3545 hidnplayr 414
 
415
        call    IPv4_find_fragment_slot
416
        cmp     esi, -1
417
        je      .dump
418
 
4052 hidnplayr 419
        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 420
        push    esi
421
        xor     eax, eax
422
        or      edi, -1
423
 
424
  .count_bytes:
4052 hidnplayr 425
        cmp     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
426
        jne     .destroy_slot_pop                                                       ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
427
        mov     cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]        ; Add total length
3545 hidnplayr 428
        xchg    cl, ch
3556 hidnplayr 429
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 430
        add     ax, cx
4052 hidnplayr 431
        movzx   cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]      ; Sub Header length
3545 hidnplayr 432
        and     cx, 0x000F
433
        shl     cx, 2
3556 hidnplayr 434
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
3545 hidnplayr 435
        sub     ax, cx
436
        mov     edi, esi
4052 hidnplayr 437
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3545 hidnplayr 438
        cmp     esi, -1
439
        jne     .count_bytes
440
 
441
        mov     esi, [esp+4]
4052 hidnplayr 442
        mov     [edi + IPv4_FRAGMENT_entry.NextPtr], esi                                ; Add this packet to the chain, this simplifies the following code
443
        mov     [esi + IPv4_FRAGMENT_entry.NextPtr], -1
444
        mov     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
445
        mov     [esi + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 446
 
4052 hidnplayr 447
        mov     cx, [edx + IPv4_header.TotalLength]                                     ; Note: This time we dont substract Header length
3545 hidnplayr 448
        xchg    cl, ch
3556 hidnplayr 449
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 450
        add     ax, cx
3556 hidnplayr 451
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
3545 hidnplayr 452
 
453
        push    eax
454
        mov     ax, [edx + IPv4_header.FlagsAndFragmentOffset]
455
        xchg    al, ah
456
        shl     ax, 3
457
        add     cx, ax
458
        pop     eax
3556 hidnplayr 459
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
3545 hidnplayr 460
 
461
        cmp     ax, cx
462
        jne     .destroy_slot_pop
463
 
464
        push    eax
465
        push    eax
466
        call    kernel_alloc
467
        test    eax, eax
468
        je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
469
        mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
470
 
471
  .rebuild_packet_loop:
4052 hidnplayr 472
        movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
3545 hidnplayr 473
        xchg    cl, ch                                                                  ;  intel byte order
474
        shl     cx, 3                                                                   ;   multiply by 8 and clear first 3 bits
3556 hidnplayr 475
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
3545 hidnplayr 476
 
477
        lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
4258 hidnplayr 478
        movzx   ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Find header size (in ebx) of fragment
3545 hidnplayr 479
        and     bx, 0x000F                                                              ;
480
        shl     bx, 2                                                                   ;
481
 
4258 hidnplayr 482
        lea     esi, [edx + sizeof.IPv4_FRAGMENT_entry]                                 ; Set esi to the correct begin of fragment
483
        movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]       ; Calculate total length of fragment
3545 hidnplayr 484
        xchg    cl, ch                                                                  ;  intel byte order
485
 
486
        cmp     edi, eax                                                                ; Is this packet the first fragment ?
487
        je      .first_fragment
488
        sub     cx, bx                                                                  ; If not, dont copy the header
489
        add     esi, ebx                                                                ;
490
  .first_fragment:
491
 
4258 hidnplayr 492
 
493
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
3545 hidnplayr 494
        push    cx                                                                      ; First copy dword-wise, then byte-wise
495
        shr     cx, 2                                                                   ;
3711 clevermous 496
        rep movsd                                                                       ;
3545 hidnplayr 497
        pop     cx                                                                      ;
498
        and     cx, 3                                                                   ;
3711 clevermous 499
        rep movsb                                                                       ;
3545 hidnplayr 500
 
501
        push    eax
4259 hidnplayr 502
        push    [edx + IPv4_FRAGMENT_entry.Owner]                                       ; we need to remeber the owner, in case this is the last packet
503
        push    [edx + IPv4_FRAGMENT_entry.NextPtr]                                     ; Set edx to the next pointer
3545 hidnplayr 504
        push    edx                                                                     ; Push pointer to fragment onto stack
4258 hidnplayr 505
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
5522 hidnplayr 506
        call    NET_BUFF_free                                                          ; free the previous fragment buffer (this uses the value from stack)
4258 hidnplayr 507
        pop     edx ebx eax
3545 hidnplayr 508
        cmp     edx, -1                                                                 ; Check if it is last fragment in chain
509
        jne     .rebuild_packet_loop
510
 
511
        pop     ecx
512
        xchg    cl, ch
513
        mov     edx, eax
514
        mov     [edx + IPv4_header.TotalLength], cx
4259 hidnplayr 515
        add     esp, 12
3545 hidnplayr 516
        xchg    cl, ch
4259 hidnplayr 517
        push    ecx edx                 ; size and pointer
518
        jmp     .handle_it              ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
3545 hidnplayr 519
 
520
  .destroy_slot_pop:
521
        add     esp, 4
522
  .destroy_slot:
3556 hidnplayr 523
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
3545 hidnplayr 524
        ; TODO!
525
        jmp     .dump
526
 
527
 
528
 
529
 
530
 
531
;-----------------------------------------------------------------
532
;
533
; find fragment slot
534
;
535
; IN: pointer to fragmented packet in edx
536
; OUT: pointer to slot in esi, -1 on error
537
;
538
;-----------------------------------------------------------------
539
align 4
540
IPv4_find_fragment_slot:
541
 
542
;;; TODO: the RFC says we should check protocol number too
543
 
544
        push    eax ebx ecx edx
545
        mov     ax, [edx + IPv4_header.Identification]
4052 hidnplayr 546
        mov     ecx, IPv4_MAX_FRAGMENTS
547
        mov     esi, IPv4_FRAGMENT_LIST
3545 hidnplayr 548
        mov     ebx, [edx + IPv4_header.SourceAddress]
549
        mov     edx, [edx + IPv4_header.DestinationAddress]
550
  .find_slot:
4052 hidnplayr 551
        cmp     [esi + IPv4_FRAGMENT_slot.id], ax
3545 hidnplayr 552
        jne     .try_next
4052 hidnplayr 553
        cmp     [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
3545 hidnplayr 554
        jne     .try_next
4052 hidnplayr 555
        cmp     [esi + IPv4_FRAGMENT_slot.DstIP], edx
3545 hidnplayr 556
        je      .found_slot
557
  .try_next:
4052 hidnplayr 558
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 559
        loop    .find_slot
560
 
561
        or      esi, -1
562
  .found_slot:
563
        pop     edx ecx ebx eax
564
        ret
565
 
566
 
567
;------------------------------------------------------------------
568
;
569
; IPv4_output
570
;
4052 hidnplayr 571
; IN:   eax = Destination IP
5584 hidnplayr 572
;       ebx = device ptr (or 0 to let IP layer decide)
4052 hidnplayr 573
;       ecx = data length
574
;       edx = Source IP
5015 hidnplayr 575
;        di = TTL shl 8 + protocol
3545 hidnplayr 576
;
5015 hidnplayr 577
; OUT:  eax = pointer to buffer start / 0 on error
578
;       ebx = device ptr (send packet through this device)
579
;       ecx = data length
580
;       edx = size of complete frame
581
;       edi = start of IPv4 payload
3545 hidnplayr 582
;
583
;------------------------------------------------------------------
584
align 4
585
IPv4_output:
586
 
3601 hidnplayr 587
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, eax
3545 hidnplayr 588
 
589
        cmp     ecx, 65500              ; Max IPv4 packet size
590
        ja      .too_large
591
 
4052 hidnplayr 592
        push    ecx di eax
593
        call    IPv4_route              ; outputs device number in edi, dest ip in eax, source IP in edx
594
        push    edx
3610 hidnplayr 595
        test    edi, edi
596
        jz      .loopback
597
 
3545 hidnplayr 598
        call    ARP_IP_to_MAC
599
        test    eax, 0xffff0000         ; error bits
600
        jnz     .arp_error
601
        push    ebx                     ; push the mac onto the stack
602
        push    ax
603
 
4052 hidnplayr 604
        inc     [IPv4_packets_tx + edi]   ; update stats
3545 hidnplayr 605
 
5015 hidnplayr 606
        mov     ax, ETHER_PROTO_IPv4
3638 hidnplayr 607
        mov     ebx, [NET_DRV_LIST + edi]
4052 hidnplayr 608
        mov     ecx, [esp + 6 + 8 + 2]
3545 hidnplayr 609
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 610
        mov     edx, esp
3545 hidnplayr 611
        call    ETH_output
612
        jz      .eth_error
613
        add     esp, 6                  ; pop the mac out of the stack
614
 
615
  .continue:
616
        xchg    cl, ch                                  ; internet byte order
617
        mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
618
        mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
619
        mov     [edi + IPv4_header.TotalLength], cx
620
        mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
621
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
4052 hidnplayr 622
 
3545 hidnplayr 623
        mov     [edi + IPv4_header.HeaderChecksum], 0
624
        popd    [edi + IPv4_header.SourceAddress]
625
        popd    [edi + IPv4_header.DestinationAddress]
626
 
4052 hidnplayr 627
        pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
628
;               [edi + IPv4_header.Protocol]
629
 
3545 hidnplayr 630
        pop     ecx
631
 
632
        IPv4_checksum edi
633
        add     edi, sizeof.IPv4_header
3556 hidnplayr 634
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
3545 hidnplayr 635
        ret
636
 
637
  .eth_error:
3603 hidnplayr 638
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
3545 hidnplayr 639
        add     esp, 3*4+2+6
5015 hidnplayr 640
        xor     eax, eax
3545 hidnplayr 641
        ret
642
 
643
  .arp_error:
3603 hidnplayr 644
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
3545 hidnplayr 645
        add     esp, 3*4+2
5015 hidnplayr 646
        xor     eax, eax
3545 hidnplayr 647
        ret
648
 
649
  .too_large:
3556 hidnplayr 650
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
5015 hidnplayr 651
        xor     eax, eax
3545 hidnplayr 652
        ret
653
 
654
  .loopback:
5522 hidnplayr 655
        mov     dword [esp], eax                        ; set source IP to dest IP
3610 hidnplayr 656
        mov     ecx, [esp + 10]
3545 hidnplayr 657
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 658
        mov     edi, AF_INET4
3545 hidnplayr 659
        call    LOOP_output
660
        jmp     .continue
661
 
662
 
663
 
664
 
665
;------------------------------------------------------------------
666
;
667
; IPv4_output_raw
668
;
669
; IN: eax = socket ptr
670
;     ecx = data length
671
;     esi = data ptr
672
;
5015 hidnplayr 673
; OUT: eax = -1 on error
3545 hidnplayr 674
;
675
;------------------------------------------------------------------
676
align 4
677
IPv4_output_raw:
678
 
679
        DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
680
 
681
        cmp     ecx, 1480               ;;;;; FIXME
682
        ja      .too_large
683
 
684
        sub     esp, 8
685
        push    esi eax
686
 
687
        call    IPv4_route
688
        call    ARP_IP_to_MAC
689
 
690
        test    eax, 0xffff0000         ; error bits
691
        jnz     .arp_error
692
 
693
        push    ebx                     ; push the mac
694
        push    ax
695
 
4052 hidnplayr 696
        inc     [IPv4_packets_tx + 4*edi]
5015 hidnplayr 697
        mov     ax, ETHER_PROTO_IPv4
3601 hidnplayr 698
        mov     ebx, [NET_DRV_LIST + 4*edi]
3545 hidnplayr 699
        mov     ecx, [esp + 6 + 4]
700
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 701
        mov     edx, esp
3545 hidnplayr 702
        call    ETH_output
703
        jz      .error
704
        add     esp, 6  ; pop the mac
705
 
706
        mov     dword[esp+4+4], edx
707
        mov     dword[esp+4+4+4], eax
708
 
709
        pop     eax esi
710
;; todo: check socket options if we should add header, or just compute checksum
711
 
712
        push    edi ecx
3711 clevermous 713
        rep movsb
3545 hidnplayr 714
        pop     ecx edi
715
 
716
;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
717
;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
718
;        [edi + IPv4_header.TotalLength]
719
;        [edi + IPv4_header.TotalLength]                ; internet byte order
720
;        [edi + IPv4_header.FlagsAndFragmentOffset]
721
 
722
        mov     [edi + IPv4_header.HeaderChecksum], 0
723
 
724
;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
725
;        [edi + IPv4_header.Protocol]
726
;        [edi + IPv4_header.Identification]             ; fragment id
727
;        [edi + IPv4_header.SourceAddress]
728
;        [edi + IPv4_header.DestinationAddress]
729
 
730
        IPv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
731
        add     edi, sizeof.IPv4_header
3556 hidnplayr 732
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
3545 hidnplayr 733
        call    [ebx + NET_DEVICE.transmit]
734
        ret
735
 
736
  .error:
737
        add     esp, 6
738
  .arp_error:
739
        add     esp, 8+4+4
740
  .too_large:
3556 hidnplayr 741
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output_raw: Failed\n"
5015 hidnplayr 742
        or      eax, -1
3545 hidnplayr 743
        ret
744
 
745
 
746
;--------------------------------------------------------
747
;
748
;
749
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
750
;     esi = pointer to ip header in that buffer
751
;     ecx = max size of fragments
752
;
753
; OUT: /
754
;
755
;--------------------------------------------------------
756
 
757
align 4
758
IPv4_fragment:
759
 
3556 hidnplayr 760
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
3545 hidnplayr 761
 
762
        and     ecx, not 111b   ; align 4
763
 
764
        cmp     ecx, sizeof.IPv4_header + 8     ; must be able to put at least 8 bytes
765
        jb      .err2
766
 
767
        push    esi ecx
768
        mov     eax, [esi + IPv4_header.DestinationAddress]
769
        call    ARP_IP_to_MAC
770
        pop     ecx esi
771
        cmp     eax, -1
772
        jz      .err2
773
 
774
        push    ebx
775
        push    ax
776
 
777
        mov     ebx, [NET_DRV_LIST]
778
        lea     eax, [ebx + ETH_DEVICE.mac]
779
        push    eax
780
 
781
 
782
        push    esi                             ; ptr to ip header
783
        sub     ecx, sizeof.IPv4_header         ; substract header size
784
        push    ecx                             ; max data size
785
        push    dword 0                         ; offset
786
 
787
  .new_fragment:
3556 hidnplayr 788
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
3545 hidnplayr 789
 
5015 hidnplayr 790
        mov     ax, ETHER_PROTO_IPv4
3545 hidnplayr 791
        lea     ebx, [esp + 4*4]
792
        call    ETH_output
793
        jz      .err
794
 
795
; copy header
796
        mov     esi, [esp + 2*4]
797
        mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
3711 clevermous 798
        rep movsd
3545 hidnplayr 799
 
800
; copy data
801
        mov     esi, [esp + 2*4]
802
        add     esi, sizeof.IPv4_header
803
        add     esi, [esp]      ; offset
804
 
805
        mov     ecx, [esp + 1*4]
3556 hidnplayr 806
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment: copying %u bytes\n", ecx
3711 clevermous 807
        rep movsb
3545 hidnplayr 808
 
809
; now, correct header
810
        mov     ecx, [esp + 1*4]
811
        add     ecx, sizeof.IPv4_header
812
        xchg    cl, ch
813
        mov     [edi + IPv4_header.TotalLength], cx
814
 
815
        mov     ecx, [esp]              ; offset
816
        xchg    cl, ch
817
 
818
;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
819
;        je      .last_fragment
820
        or      cx, 1 shl 2             ; more fragments
821
;  .last_fragment:
822
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], cx
823
 
824
        mov     [edi + IPv4_header.HeaderChecksum], 0
825
 
826
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
827
        mov     ecx, [esp + 1*4]
828
 
829
        push    edx eax
830
        IPv4_checksum edi
831
 
832
        call    [ebx + NET_DEVICE.transmit]
833
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
834
 
3711 clevermous 835
        mov     ecx, [esp+4]
3545 hidnplayr 836
        add     [esp], ecx
837
 
838
        mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
839
        add     ecx, [esp+3*4+6+4+4]    ; buff size
840
        sub     ecx, [esp+2*4]          ; ptr to ip header
841
        add     ecx, [esp]              ; offset
842
 
3556 hidnplayr 843
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: %u bytes remaining\n", ecx
3545 hidnplayr 844
 
845
        cmp     ecx, [esp+1*4]
846
        jae     .new_fragment
847
 
848
        mov     [esp+4], ecx            ; set fragment size to remaining packet size
849
        jmp     .new_fragment
850
 
851
      .err:
3556 hidnplayr 852
        DEBUGF  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
3545 hidnplayr 853
      .done:
854
        add     esp, 12 + 4 + 6
855
      .err2:
3556 hidnplayr 856
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: dumping\n"
5522 hidnplayr 857
        call    NET_BUFF_free
3545 hidnplayr 858
        ret
859
 
860
 
861
 
862
;---------------------------------------------------------------------------
863
;
864
; IPv4_route
865
;
866
; IN:   eax = Destination IP
5584 hidnplayr 867
;       ebx = outgoing device / 0
4052 hidnplayr 868
;       edx = Source IP
869
; OUT:  eax = Destination IP (or gateway IP)
870
;       edx = Source IP
871
;       edi = device number*4
872
; DESTROYED:
873
;       ecx
3545 hidnplayr 874
;
875
;---------------------------------------------------------------------------
876
align 4
4052 hidnplayr 877
IPv4_route:     ; TODO: return error if no valid route found
3545 hidnplayr 878
 
5584 hidnplayr 879
        test    ebx, ebx
880
        jnz     .got_device
881
 
3545 hidnplayr 882
        cmp     eax, 0xffffffff
883
        je      .broadcast
884
 
885
        xor     edi, edi
886
  .loop:
4052 hidnplayr 887
        mov     ebx, [IP_LIST + edi]
888
        and     ebx, [SUBNET_LIST + edi]
3545 hidnplayr 889
        jz      .next
4052 hidnplayr 890
        mov     ecx, eax
891
        and     ecx, [SUBNET_LIST + edi]
892
        cmp     ebx, ecx
893
        je      .got_it
3545 hidnplayr 894
  .next:
895
        add     edi, 4
4052 hidnplayr 896
        cmp     edi, 4*NET_DEVICES_MAX
897
        jb      .loop
3545 hidnplayr 898
 
4052 hidnplayr 899
        mov     eax, [GATEWAY_LIST + 4]         ; TODO: let user (or a user space daemon) configure default route
3545 hidnplayr 900
  .broadcast:
4052 hidnplayr 901
        mov     edi, 4                          ; TODO: same as above
902
  .got_it:
903
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
904
        test    edx, edx
905
        jnz     @f
906
        mov     edx, [IP_LIST + edi]
907
  @@:
908
 
3545 hidnplayr 909
        ret
910
 
5584 hidnplayr 911
  .got_device:
912
; Validate device ptr and convert to device number
913
        call    NET_ptr_to_num4
914
        cmp     edi, -1
915
        je      .fail
3545 hidnplayr 916
 
5584 hidnplayr 917
        mov     edx, [IP_LIST + edi]            ; Source IP
3545 hidnplayr 918
 
5584 hidnplayr 919
; Check if we should route to gateway or not
920
        mov     ebx, [IP_LIST + edi]
921
        and     ebx, [SUBNET_LIST + edi]
922
        mov     ecx, eax
923
        and     ecx, [SUBNET_LIST + edi]
924
        je      @f
925
        mov     eax, [GATEWAY_LIST + edi]
926
  @@:
927
        ret
928
 
929
  .fail:
930
        ret
931
 
932
 
933
 
3545 hidnplayr 934
;---------------------------------------------------------------------------
935
;
936
; IPv4_get_frgmnt_num
937
;
938
; IN: /
939
; OUT: fragment number in ax
940
;
941
;---------------------------------------------------------------------------
942
align 4
943
IPv4_get_frgmnt_num:
944
        xor     ax, ax  ;;; TODO: replace this with real code
945
 
946
        ret
947
 
948
 
4030 hidnplayr 949
;-----------------------------------------------------------------
950
;
951
; IPv4_connect
952
;
953
;   IN: eax = socket pointer
954
;  OUT: eax = 0 ok / -1 error
955
;       ebx = error code
956
;
957
;-------------------------
958
align 4
959
IPv4_connect:
960
 
4035 hidnplayr 961
        push    eax edx
4030 hidnplayr 962
        lea     ecx, [eax + SOCKET.mutex]
963
        call    mutex_lock
4035 hidnplayr 964
        pop     edx eax
4030 hidnplayr 965
 
966
; Fill in local IP
967
        cmp     [eax + IP_SOCKET.LocalIP], 0
968
        jne     @f
969
        push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
970
        pop     [eax + IP_SOCKET.LocalIP]
971
 
972
; Fill in remote IP
973
        pushd   [edx + 4]
974
        pop     [eax + IP_SOCKET.RemoteIP]
975
 
4035 hidnplayr 976
; Set up data receiving queue
4030 hidnplayr 977
        push    eax
4035 hidnplayr 978
        init_queue (eax + SOCKET_QUEUE_LOCATION)
4030 hidnplayr 979
        pop     eax
980
 
981
        lea     ecx, [eax + SOCKET.mutex]
982
        call    mutex_unlock
983
 
984
        xor     eax, eax
985
        ret
986
 
987
 
3545 hidnplayr 988
;---------------------------------------------------------------------------
989
;
990
; IPv4_API
991
;
992
; This function is called by system function 75
993
;
994
; IN:  subfunction number in bl
995
;      device number in bh
996
;      ecx, edx, .. depends on subfunction
997
;
998
; OUT:
999
;
1000
;---------------------------------------------------------------------------
1001
align 4
1002
IPv4_api:
1003
 
1004
        movzx   eax, bh
1005
        shl     eax, 2
1006
 
1007
        and     ebx, 0x000000ff
1008
        cmp     ebx, .number
1009
        ja      .error
1010
        jmp     dword [.table + 4*ebx]
1011
 
1012
  .table:
1013
        dd      .packets_tx     ; 0
1014
        dd      .packets_rx     ; 1
1015
        dd      .read_ip        ; 2
1016
        dd      .write_ip       ; 3
1017
        dd      .read_dns       ; 4
1018
        dd      .write_dns      ; 5
1019
        dd      .read_subnet    ; 6
1020
        dd      .write_subnet   ; 7
1021
        dd      .read_gateway   ; 8
1022
        dd      .write_gateway  ; 9
1023
  .number = ($ - .table) / 4 - 1
1024
 
1025
  .error:
1026
        mov     eax, -1
1027
        ret
1028
 
1029
  .packets_tx:
4052 hidnplayr 1030
        mov     eax, [IPv4_packets_tx + eax]
3545 hidnplayr 1031
        ret
1032
 
1033
  .packets_rx:
4052 hidnplayr 1034
        mov     eax, [IPv4_packets_rx + eax]
3545 hidnplayr 1035
        ret
1036
 
1037
  .read_ip:
1038
        mov     eax, [IP_LIST + eax]
1039
        ret
1040
 
1041
  .write_ip:
1042
        mov     [IP_LIST + eax], ecx
1043
        mov     edi, eax                        ; device number, we'll need it for ARP
1044
 
1045
        ; pre-calculate the local broadcast address
1046
        mov     ebx, [SUBNET_LIST + eax]
1047
        not     ebx
1048
        or      ebx, ecx
1049
        mov     [BROADCAST_LIST + eax], ebx
1050
 
3601 hidnplayr 1051
        mov     ebx, [NET_DRV_LIST + eax]
1052
        mov     eax, [IP_LIST + eax]
3545 hidnplayr 1053
        call    ARP_output_request              ; now send a gratuitous ARP
1054
 
1055
        call    NET_send_event
1056
        xor     eax, eax
1057
        ret
1058
 
1059
  .read_dns:
1060
        mov     eax, [DNS_LIST + eax]
1061
        ret
1062
 
1063
  .write_dns:
1064
        mov     [DNS_LIST + eax], ecx
1065
        call    NET_send_event
1066
        xor     eax, eax
1067
        ret
1068
 
1069
  .read_subnet:
1070
        mov     eax, [SUBNET_LIST + eax]
1071
        ret
1072
 
1073
  .write_subnet:
1074
        mov     [SUBNET_LIST + eax], ecx
1075
 
1076
        ; pre-calculate the local broadcast address
1077
        mov     ebx, [IP_LIST + eax]
1078
        not     ecx
1079
        or      ecx, ebx
1080
        mov     [BROADCAST_LIST + eax], ecx
1081
 
1082
        call    NET_send_event
1083
        xor     eax, eax
1084
        ret
1085
 
1086
  .read_gateway:
1087
        mov     eax, [GATEWAY_LIST + eax]
1088
        ret
1089
 
1090
  .write_gateway:
1091
        mov     [GATEWAY_LIST + eax], ecx
1092
 
1093
        call    NET_send_event
1094
        xor     eax, eax
1095
        ret