Subversion Repositories Kolibri OS

Rev

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