Subversion Repositories Kolibri OS

Rev

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

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