Subversion Repositories Kolibri OS

Rev

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

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