Subversion Repositories Kolibri OS

Rev

Rev 9815 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
9800 Boppan 3
;; Copyright (C) KolibriOS team 2004-2022. 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: 9817 $
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
9799 Boppan 396
        cmp     edi, [esi + sizeof.NET_BUFF + 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
9799 Boppan 399
        mov     esi, [esi + sizeof.NET_BUFF + 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
9799 Boppan 406
        mov     [edi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr], eax        ; update pointer of previous entry to the new entry
407
        mov     [eax + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr], -1
408
        mov     [eax + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.PrevPtr], edi
409
        mov     [eax + sizeof.NET_BUFF + 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
9799 Boppan 440
        mov     [eax + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr], -1
441
        mov     [eax + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.PrevPtr], -1
442
        mov     [eax + sizeof.NET_BUFF + 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
9814 Boppan 458
        push    esi                                                     ; Save pointer to first buffer on stack
459
        push    edi                                                     ; Save device index on stack
3545 hidnplayr 460
        xor     eax, eax
461
        or      edi, -1
462
 
463
  .count_bytes:
9799 Boppan 464
        cmp     [esi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.PrevPtr], edi
4052 hidnplayr 465
        jne     .destroy_slot_pop                                                       ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
9799 Boppan 466
        mov     cx, [esi + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]        ; Add total length
3545 hidnplayr 467
        xchg    cl, ch
3556 hidnplayr 468
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 469
        add     ax, cx
9799 Boppan 470
        movzx   cx, [esi + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]      ; Sub Header length
3545 hidnplayr 471
        and     cx, 0x000F
472
        shl     cx, 2
3556 hidnplayr 473
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
3545 hidnplayr 474
        sub     ax, cx
475
        mov     edi, esi
9799 Boppan 476
        mov     esi, [esi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr]
3545 hidnplayr 477
        cmp     esi, -1
478
        jne     .count_bytes
479
 
9814 Boppan 480
        mov     esi, [esp+8]                                                                              ; Take the current (last) buffer pointer
9799 Boppan 481
        mov     [edi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr], esi                                ; Add this packet to the chain, this simplifies the following code
482
        mov     [esi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr], -1
483
        mov     [esi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.PrevPtr], edi
484
        mov     [esi + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.Owner], ebx
3545 hidnplayr 485
 
4052 hidnplayr 486
        mov     cx, [edx + IPv4_header.TotalLength]                                     ; Note: This time we dont substract Header length
3545 hidnplayr 487
        xchg    cl, ch
3556 hidnplayr 488
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3545 hidnplayr 489
        add     ax, cx
3556 hidnplayr 490
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
3545 hidnplayr 491
 
492
        push    eax
493
        mov     ax, [edx + IPv4_header.FlagsAndFragmentOffset]
9736 Boppan 494
        xchg    al, ah
9729 Boppan 495
        shl     ax, 3
3545 hidnplayr 496
        add     cx, ax
497
        pop     eax
3556 hidnplayr 498
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
3545 hidnplayr 499
 
500
        cmp     ax, cx
501
        jne     .destroy_slot_pop
502
 
9814 Boppan 503
        push    eax                                                                     ; Save total size of packet on stack
3545 hidnplayr 504
        push    eax
505
        call    kernel_alloc
506
        test    eax, eax
9814 Boppan 507
        je      .destroy_slot_pop12                                                     ; If we dont have enough space to allocate the buffer, discard all packets in slot
508
        mov     edx, [esp+8]                                                            ; Get pointer to first fragment entry back in edx
3545 hidnplayr 509
 
9809 Boppan 510
        ; FIXME: Allocate NET_BUFF here instead of raw IP packet buffer
9807 Boppan 511
 
3545 hidnplayr 512
  .rebuild_packet_loop:
9799 Boppan 513
        movzx   ecx, [edx + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
3545 hidnplayr 514
        xchg    cl, ch                                                                  ;  intel byte order
515
        shl     cx, 3                                                                   ;   multiply by 8 and clear first 3 bits
3556 hidnplayr 516
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
3545 hidnplayr 517
 
518
        lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
9799 Boppan 519
        movzx   ebx, [edx + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Find header size (in ebx) of fragment
3545 hidnplayr 520
        and     bx, 0x000F                                                              ;
521
        shl     bx, 2                                                                   ;
522
 
9799 Boppan 523
        lea     esi, [edx + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry]                                 ; Set esi to the correct begin of fragment
524
        movzx   ecx, [edx + sizeof.NET_BUFF + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]       ; Calculate total length of fragment
3545 hidnplayr 525
        xchg    cl, ch                                                                  ;  intel byte order
526
 
527
        cmp     edi, eax                                                                ; Is this packet the first fragment ?
528
        je      .first_fragment
529
        sub     cx, bx                                                                  ; If not, dont copy the header
530
        add     esi, ebx                                                                ;
9806 Boppan 531
        add     edi, ebx                                                                ; FIXME: We should add size of header of first fragment here
532
                                                                                        ; instead of size of currently copying fragment
533
                                                                                        ; because the fragment offset is offset within the big IP packet
534
                                                                                        ; data (not within the packet, within packet's contents)
3545 hidnplayr 535
  .first_fragment:
536
 
4258 hidnplayr 537
 
538
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
3545 hidnplayr 539
        push    cx                                                                      ; First copy dword-wise, then byte-wise
540
        shr     cx, 2                                                                   ;
3711 clevermous 541
        rep movsd                                                                       ;
3545 hidnplayr 542
        pop     cx                                                                      ;
543
        and     cx, 3                                                                   ;
3711 clevermous 544
        rep movsb                                                                       ;
3545 hidnplayr 545
 
546
        push    eax
9799 Boppan 547
        push    [edx + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.Owner]                                       ; we need to remeber the owner, in case this is the last packet
548
        push    [edx + sizeof.NET_BUFF + IPv4_FRAGMENT_entry.NextPtr]                                     ; Set edx to the next pointer
3545 hidnplayr 549
        push    edx                                                                     ; Push pointer to fragment onto stack
4258 hidnplayr 550
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
6011 hidnplayr 551
        call    net_buff_free                                                          ; free the previous fragment buffer (this uses the value from stack)
4258 hidnplayr 552
        pop     edx ebx eax
3545 hidnplayr 553
        cmp     edx, -1                                                                 ; Check if it is last fragment in chain
554
        jne     .rebuild_packet_loop
555
 
9814 Boppan 556
        pop     ecx                     ; Restore the total size of IP packet
557
        pop     edi                     ; Restore the device index
3545 hidnplayr 558
        xchg    cl, ch
559
        mov     edx, eax
560
        mov     [edx + IPv4_header.TotalLength], cx
9807 Boppan 561
        add     esp, 8                  ; Remove pointer to first buffer and pointer to last buffer from the stack
3545 hidnplayr 562
        xchg    cl, ch
9807 Boppan 563
        push    edx                     ; Push pointer to the new buffer with full IP packet
9809 Boppan 564
 
565
; FIXME: Remove this block once allocated network buffers handling is implemented.
566
if 1
9817 Boppan 567
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_input: fragmented packet of size %d is dropped\n", ecx
9809 Boppan 568
        call    kernel_free             ; Ptr to buffer is on the stack already
569
        inc     [IPv4_packets_dumped + edi]
570
        ret
571
end if
572
 
9807 Boppan 573
        jmp     .handle_it              ; edx = buf ptr, ecx = size, [esp] buf ptr, ebx=device ptr
3545 hidnplayr 574
 
9814 Boppan 575
  .destroy_slot_pop12:
576
        add     esp, 4 ; Remove total size from the stack
3545 hidnplayr 577
  .destroy_slot_pop:
9814 Boppan 578
        pop     edi    ; Restore device index
579
        add     esp, 4 ; Remove first buffer pointer from the stack
3545 hidnplayr 580
  .destroy_slot:
3556 hidnplayr 581
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
9814 Boppan 582
        ; TODO: What?
583
        ; Last buffer pointer is on the stack now
3545 hidnplayr 584
        jmp     .dump
585
 
586
 
587
 
588
 
589
 
6011 hidnplayr 590
;-----------------------------------------------------------------;
591
;                                                                 ;
592
; ipv4_find_fragment_slot                                         ;
593
;                                                                 ;
594
; IN: pointer to fragmented packet in edx                         ;
595
;                                                                 ;
596
; OUT: pointer to slot in esi, -1 on error                        ;
597
;                                                                 ;
598
;-----------------------------------------------------------------;
3545 hidnplayr 599
align 4
6011 hidnplayr 600
ipv4_find_fragment_slot:
3545 hidnplayr 601
 
602
;;; TODO: the RFC says we should check protocol number too
603
 
604
        push    eax ebx ecx edx
605
        mov     ax, [edx + IPv4_header.Identification]
4052 hidnplayr 606
        mov     ecx, IPv4_MAX_FRAGMENTS
7678 hidnplayr 607
        mov     esi, IPv4_fragments
3545 hidnplayr 608
        mov     ebx, [edx + IPv4_header.SourceAddress]
609
        mov     edx, [edx + IPv4_header.DestinationAddress]
610
  .find_slot:
4052 hidnplayr 611
        cmp     [esi + IPv4_FRAGMENT_slot.id], ax
3545 hidnplayr 612
        jne     .try_next
4052 hidnplayr 613
        cmp     [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
3545 hidnplayr 614
        jne     .try_next
4052 hidnplayr 615
        cmp     [esi + IPv4_FRAGMENT_slot.DstIP], edx
3545 hidnplayr 616
        je      .found_slot
617
  .try_next:
4052 hidnplayr 618
        add     esi, sizeof.IPv4_FRAGMENT_slot
3545 hidnplayr 619
        loop    .find_slot
620
 
621
        or      esi, -1
622
  .found_slot:
623
        pop     edx ecx ebx eax
624
        ret
625
 
626
 
6011 hidnplayr 627
;------------------------------------------------------------------;
628
;                                                                  ;
629
; ipv4_output                                                      ;
630
;                                                                  ;
631
;  IN:  al = protocol                                              ;
632
;       ah = TTL                                                   ;
633
;       ebx = device ptr (or 0 to let IP layer decide)             ;
634
;       ecx = data length                                          ;
635
;       edx = Source IP                                            ;
636
;       edi = Destination IP                                       ;
637
;                                                                  ;
638
; OUT:  eax = pointer to buffer start                              ;
639
;       eax = 0 on error                                           ;
640
;       ebx = device ptr (send packet through this device)         ;
641
;       ecx = data length                                          ;
642
;       edx = size of complete frame                               ;
643
;       edi = start of IPv4 payload                                ;
644
;                                                                  ;
645
;------------------------------------------------------------------;
3545 hidnplayr 646
align 4
6011 hidnplayr 647
ipv4_output:
3545 hidnplayr 648
 
6475 hidnplayr 649
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, edi
3545 hidnplayr 650
 
651
        cmp     ecx, 65500              ; Max IPv4 packet size
652
        ja      .too_large
653
 
5842 hidnplayr 654
        push    ecx ax edi
655
        mov     eax, edi
6011 hidnplayr 656
        call    ipv4_route              ; outputs device number in edi, dest ip in eax, source IP in edx
6122 hidnplayr 657
        test    eax, eax
658
        jz      .no_route
4052 hidnplayr 659
        push    edx
3610 hidnplayr 660
        test    edi, edi
661
        jz      .loopback
662
 
6011 hidnplayr 663
        call    arp_ip_to_mac
3545 hidnplayr 664
        test    eax, 0xffff0000         ; error bits
665
        jnz     .arp_error
666
        push    ebx                     ; push the mac onto the stack
667
        push    ax
668
 
5842 hidnplayr 669
        inc     [IPv4_packets_tx + edi] ; update stats
3545 hidnplayr 670
 
5015 hidnplayr 671
        mov     ax, ETHER_PROTO_IPv4
7679 hidnplayr 672
        mov     ebx, [net_device_list + edi]
4052 hidnplayr 673
        mov     ecx, [esp + 6 + 8 + 2]
3545 hidnplayr 674
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 675
        mov     edx, esp
6011 hidnplayr 676
        call    eth_output
3545 hidnplayr 677
        jz      .eth_error
678
        add     esp, 6                  ; pop the mac out of the stack
679
 
680
  .continue:
681
        xchg    cl, ch                                  ; internet byte order
682
        mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
683
        mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
684
        mov     [edi + IPv4_header.TotalLength], cx
685
        mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
686
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
4052 hidnplayr 687
 
3545 hidnplayr 688
        mov     [edi + IPv4_header.HeaderChecksum], 0
689
        popd    [edi + IPv4_header.SourceAddress]
690
        popd    [edi + IPv4_header.DestinationAddress]
691
 
4052 hidnplayr 692
        pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
693
;               [edi + IPv4_header.Protocol]
694
 
3545 hidnplayr 695
        pop     ecx
696
 
6011 hidnplayr 697
        ipv4_checksum edi
3545 hidnplayr 698
        add     edi, sizeof.IPv4_header
3556 hidnplayr 699
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
3545 hidnplayr 700
        ret
701
 
702
  .eth_error:
3603 hidnplayr 703
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
3545 hidnplayr 704
        add     esp, 3*4+2+6
5015 hidnplayr 705
        xor     eax, eax
3545 hidnplayr 706
        ret
707
 
6122 hidnplayr 708
  .no_route:
709
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: No route to host!\n"
710
        add     esp, 2*4+2
711
        xor     eax, eax
712
        ret
713
 
3545 hidnplayr 714
  .arp_error:
3603 hidnplayr 715
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
5842 hidnplayr 716
        add     esp, 4
717
        pop     eax
718
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ip=0x%x\n", eax
719
        add     esp, 4+2
5015 hidnplayr 720
        xor     eax, eax
3545 hidnplayr 721
        ret
722
 
723
  .too_large:
3556 hidnplayr 724
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
5015 hidnplayr 725
        xor     eax, eax
3545 hidnplayr 726
        ret
727
 
728
  .loopback:
7678 hidnplayr 729
        inc     [IPv4_packets_tx + edi]                 ; update stats
730
 
5522 hidnplayr 731
        mov     dword [esp], eax                        ; set source IP to dest IP
3610 hidnplayr 732
        mov     ecx, [esp + 10]
3545 hidnplayr 733
        add     ecx, sizeof.IPv4_header
3600 hidnplayr 734
        mov     edi, AF_INET4
6011 hidnplayr 735
        call    loop_output
3545 hidnplayr 736
        jmp     .continue
737
 
738
 
739
 
740
 
6011 hidnplayr 741
;------------------------------------------------------------------;
742
;                                                                  ;
743
; ipv4_output_raw                                                  ;
744
;                                                                  ;
745
;  IN: eax = socket ptr                                            ;
746
;      ecx = data length                                           ;
747
;      esi = data ptr                                              ;
748
;                                                                  ;
749
; OUT: eax = -1 on error                                           ;
750
;                                                                  ;
751
;------------------------------------------------------------------;
3545 hidnplayr 752
align 4
6011 hidnplayr 753
ipv4_output_raw:
3545 hidnplayr 754
 
755
        DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
756
 
757
        sub     esp, 8
758
        push    esi eax
759
 
6011 hidnplayr 760
        call    ipv4_route
761
        call    arp_ip_to_mac
3545 hidnplayr 762
 
763
        test    eax, 0xffff0000         ; error bits
764
        jnz     .arp_error
765
 
766
        push    ebx                     ; push the mac
767
        push    ax
768
 
4052 hidnplayr 769
        inc     [IPv4_packets_tx + 4*edi]
5015 hidnplayr 770
        mov     ax, ETHER_PROTO_IPv4
7679 hidnplayr 771
        mov     ebx, [net_device_list + 4*edi]
3545 hidnplayr 772
        mov     ecx, [esp + 6 + 4]
773
        add     ecx, sizeof.IPv4_header
5015 hidnplayr 774
        mov     edx, esp
6011 hidnplayr 775
        call    eth_output
3545 hidnplayr 776
        jz      .error
777
        add     esp, 6  ; pop the mac
778
 
779
        mov     dword[esp+4+4], edx
780
        mov     dword[esp+4+4+4], eax
781
 
782
        pop     eax esi
5842 hidnplayr 783
;; TODO: check socket options if we should add header, or just compute checksum
3545 hidnplayr 784
 
785
        push    edi ecx
3711 clevermous 786
        rep movsb
3545 hidnplayr 787
        pop     ecx edi
788
 
789
;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
790
;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
791
;        [edi + IPv4_header.TotalLength]
792
;        [edi + IPv4_header.TotalLength]                ; internet byte order
793
;        [edi + IPv4_header.FlagsAndFragmentOffset]
794
 
795
        mov     [edi + IPv4_header.HeaderChecksum], 0
796
 
797
;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
798
;        [edi + IPv4_header.Protocol]
799
;        [edi + IPv4_header.Identification]             ; fragment id
800
;        [edi + IPv4_header.SourceAddress]
801
;        [edi + IPv4_header.DestinationAddress]
802
 
6011 hidnplayr 803
        ipv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
3545 hidnplayr 804
        add     edi, sizeof.IPv4_header
3556 hidnplayr 805
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
3545 hidnplayr 806
        call    [ebx + NET_DEVICE.transmit]
807
        ret
808
 
809
  .error:
5842 hidnplayr 810
        add     esp, 6+8+4+4
811
        mov     ebx, ENOBUFS            ; FIXME: NOBUFS or MSGSIZE error
812
        or      eax, -1
813
        ret
814
 
3545 hidnplayr 815
  .arp_error:
816
        add     esp, 8+4+4
5842 hidnplayr 817
        mov     ebx, ENOTCONN
5015 hidnplayr 818
        or      eax, -1
3545 hidnplayr 819
        ret
820
 
821
 
6011 hidnplayr 822
;-----------------------------------------------------------------;
823
;                                                                 ;
824
; ipv4_fragment                                                   ;
825
;                                                                 ;
826
;  IN:  [esp] = ptr to packet buffer to fragment                  ;
827
;       edi = ptrr to ip header in that buffer                    ;
828
;       ebx = device ptr                                          ;
829
;                                                                 ;
830
;  OUT: /                                                         ;
831
;                                                                 ;
832
;-----------------------------------------------------------------;
833
proc ipv4_fragment stdcall buffer
3545 hidnplayr 834
 
5842 hidnplayr 835
locals
836
        offset          dd ?
837
        headerlength    dd ?
838
        headerptr       dd ?
839
        dataptr         dd ?
840
        remaining       dd ?
841
        segmentsize     dd ?
842
endl
3545 hidnplayr 843
 
3556 hidnplayr 844
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
3545 hidnplayr 845
 
5842 hidnplayr 846
; We must be able to put at least 8 bytes per segment
847
        movzx   eax, byte[edi]          ; IHL
848
        and     eax, 0xf
849
        shl     eax, 2
850
        mov     [headerlength], eax
851
        add     eax, 8
852
        mov     ecx, [ebx + NET_DEVICE.mtu]
853
        and     ecx, not 11b
854
        cmp     ecx, eax
855
        jb      .fail
3545 hidnplayr 856
 
5842 hidnplayr 857
        mov     [edi + IPv4_header.HeaderChecksum], 0
3545 hidnplayr 858
 
5842 hidnplayr 859
        mov     [segmentsize], ecx
860
        mov     [headerptr], edi
861
        movzx   ecx, [edi + IPv4_header.TotalLength]
862
        xchg    cl, ch
863
        sub     ecx, [headerlength]
864
        mov     [remaining], ecx
865
        mov     [offset], 0
3545 hidnplayr 866
 
5842 hidnplayr 867
        add     edi, [headerlength]
868
        mov     [dataptr], edi
3545 hidnplayr 869
 
5842 hidnplayr 870
  .loop:
871
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
3545 hidnplayr 872
 
5842 hidnplayr 873
        mov     ecx, [segmentsize]
874
        cmp     ecx, [remaining]
875
        jbe     @f
876
        mov     ecx, [remaining]
877
  @@:
3545 hidnplayr 878
 
5015 hidnplayr 879
        mov     ax, ETHER_PROTO_IPv4
5842 hidnplayr 880
        mov     edx, [esp]
881
        add     edx, [edx + NET_BUFF.offset]
882
;        add     edx, ETH_header.DstMAC         ; = 0
3545 hidnplayr 883
        call    ETH_output
5842 hidnplayr 884
        jz      .fail
3545 hidnplayr 885
 
5842 hidnplayr 886
        push    edi
887
        mov     edx, ecx
888
 
3545 hidnplayr 889
; copy header
5842 hidnplayr 890
        mov     esi, [headerptr]
891
        mov     ecx, [headerlength]
892
        shr     ecx, 2
3711 clevermous 893
        rep movsd
3545 hidnplayr 894
 
895
; copy data
5842 hidnplayr 896
        mov     esi, [dataptr]
897
        add     esi, [offset]
898
        mov     ecx, edx
899
        sub     ecx, [headerlength]
900
        shr     ecx, 2
901
        rep movsd
902
        pop     edi
3545 hidnplayr 903
 
904
; now, correct header
5842 hidnplayr 905
; packet length
906
        mov     ax, dx
907
        xchg    al, ah
908
        mov     [edi + IPv4_header.TotalLength], ax
3545 hidnplayr 909
 
5842 hidnplayr 910
; offset
911
        mov     eax, [offset]
912
        xchg    al, ah
3545 hidnplayr 913
 
5842 hidnplayr 914
        sub     edx, [headerlength]
915
        sub     [remaining], edx
916
        je      @f
917
        jb      .fail
918
        or      ah, 1 shl 2             ; more fragments
919
        add     [offset], edx
920
  @@:
921
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], ax
3545 hidnplayr 922
 
5842 hidnplayr 923
; Send the fragment
3545 hidnplayr 924
        IPv4_checksum edi
925
        call    [ebx + NET_DEVICE.transmit]
926
 
5842 hidnplayr 927
        cmp     [remaining], 0
928
        jne     .loop
3545 hidnplayr 929
 
5842 hidnplayr 930
        call    NET_BUFF_free
931
        ret
3545 hidnplayr 932
 
5842 hidnplayr 933
      .fail:
3556 hidnplayr 934
        DEBUGF  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
5522 hidnplayr 935
        call    NET_BUFF_free
3545 hidnplayr 936
        ret
937
 
5842 hidnplayr 938
endp
3545 hidnplayr 939
 
940
 
5842 hidnplayr 941
 
6011 hidnplayr 942
;-----------------------------------------------------------------;
943
;                                                                 ;
944
; ipv4_route                                                      ;
945
;                                                                 ;
946
; IN:   eax = Destination IP                                      ;
947
;       ebx = outgoing device / 0                                 ;
948
;       edx = Source IP                                           ;
949
;                                                                 ;
6122 hidnplayr 950
; OUT:  eax = Destination IP (may be gateway), 0 on error         ;
6011 hidnplayr 951
;       edx = Source IP                                           ;
952
;       edi = device number*4                                     ;
953
;                                                                 ;
954
; DESTROYED:                                                      ;
955
;       ecx                                                       ;
956
;                                                                 ;
957
;-----------------------------------------------------------------;
3545 hidnplayr 958
align 4
6122 hidnplayr 959
ipv4_route:
3545 hidnplayr 960
 
5584 hidnplayr 961
        test    ebx, ebx
962
        jnz     .got_device
963
 
6220 hidnplayr 964
; Broadcast does not need gateway
3545 hidnplayr 965
        cmp     eax, 0xffffffff
966
        je      .broadcast
967
 
968
        xor     edi, edi
969
  .loop:
7678 hidnplayr 970
        mov     ebx, [IPv4_address + edi]
971
        and     ebx, [IPv4_subnet + edi]
3545 hidnplayr 972
        jz      .next
4052 hidnplayr 973
        mov     ecx, eax
7678 hidnplayr 974
        and     ecx, [IPv4_subnet + edi]
4052 hidnplayr 975
        cmp     ebx, ecx
976
        je      .got_it
3545 hidnplayr 977
  .next:
978
        add     edi, 4
4052 hidnplayr 979
        cmp     edi, 4*NET_DEVICES_MAX
980
        jb      .loop
3545 hidnplayr 981
 
7678 hidnplayr 982
        mov     eax, [IPv4_gateway + 4]         ; TODO: let user (or a user space daemon) configure default route
3545 hidnplayr 983
  .broadcast:
4052 hidnplayr 984
        mov     edi, 4                          ; TODO: same as above
985
  .got_it:
986
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
987
        test    edx, edx
988
        jnz     @f
7678 hidnplayr 989
        mov     edx, [IPv4_address + edi]
4052 hidnplayr 990
  @@:
991
 
3545 hidnplayr 992
        ret
993
 
5584 hidnplayr 994
  .got_device:
995
; Validate device ptr and convert to device number
6011 hidnplayr 996
        call    net_ptr_to_num4
5584 hidnplayr 997
        cmp     edi, -1
998
        je      .fail
3545 hidnplayr 999
 
7678 hidnplayr 1000
        mov     edx, [IPv4_address + edi]            ; Source IP
3545 hidnplayr 1001
 
6220 hidnplayr 1002
; Broadcast does not need gateway
1003
        cmp     eax, 0xffffffff
1004
        je      @f
1005
 
5584 hidnplayr 1006
; Check if we should route to gateway or not
7678 hidnplayr 1007
        mov     ebx, [IPv4_address + edi]
1008
        and     ebx, [IPv4_subnet + edi]
5584 hidnplayr 1009
        mov     ecx, eax
7678 hidnplayr 1010
        and     ecx, [IPv4_subnet + edi]
6475 hidnplayr 1011
        cmp     ecx, ebx
5584 hidnplayr 1012
        je      @f
7678 hidnplayr 1013
        mov     eax, [IPv4_gateway + edi]
5584 hidnplayr 1014
  @@:
6475 hidnplayr 1015
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
5584 hidnplayr 1016
        ret
1017
 
1018
  .fail:
6475 hidnplayr 1019
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_route failed\n"
6122 hidnplayr 1020
        xor     eax, eax
5584 hidnplayr 1021
        ret
1022
 
1023
 
1024
 
6011 hidnplayr 1025
;-----------------------------------------------------------------;
1026
;                                                                 ;
1027
; ipv4_get_frgmnt_num                                             ;
1028
;                                                                 ;
1029
;  IN: /                                                          ;
1030
;                                                                 ;
1031
; OUT: ax = fragment number                                       ;
1032
;                                                                 ;
1033
;-----------------------------------------------------------------;
3545 hidnplayr 1034
align 4
6011 hidnplayr 1035
ipv4_get_frgmnt_num:
3545 hidnplayr 1036
        xor     ax, ax  ;;; TODO: replace this with real code
1037
 
1038
        ret
1039
 
1040
 
6011 hidnplayr 1041
;-----------------------------------------------------------------;
1042
;                                                                 ;
1043
; ipv4_connect                                                    ;
1044
;                                                                 ;
1045
;   IN: eax = socket pointer                                      ;
1046
;                                                                 ;
1047
;  OUT: eax = 0 on success                                        ;
1048
;       eax = -1 on error                                         ;
1049
;       ebx = error code on error                                 ;
1050
;                                                                 ;
1051
;-----------------------------------------------------------------;
4030 hidnplayr 1052
align 4
6011 hidnplayr 1053
ipv4_connect:
4030 hidnplayr 1054
 
4035 hidnplayr 1055
        push    eax edx
4030 hidnplayr 1056
        lea     ecx, [eax + SOCKET.mutex]
1057
        call    mutex_lock
4035 hidnplayr 1058
        pop     edx eax
4030 hidnplayr 1059
 
1060
; Fill in local IP
1061
        cmp     [eax + IP_SOCKET.LocalIP], 0
1062
        jne     @f
7678 hidnplayr 1063
        push    [IPv4_address + 4]                                   ; FIXME: use correct local IP
4030 hidnplayr 1064
        pop     [eax + IP_SOCKET.LocalIP]
1065
 
1066
; Fill in remote IP
1067
        pushd   [edx + 4]
1068
        pop     [eax + IP_SOCKET.RemoteIP]
1069
 
1070
        lea     ecx, [eax + SOCKET.mutex]
1071
        call    mutex_unlock
1072
 
1073
        xor     eax, eax
1074
        ret
1075
 
1076
 
6011 hidnplayr 1077
;-----------------------------------------------------------------;
1078
;                                                                 ;
1079
; ipv4_API: Part of system function 76.                           ;
1080
;                                                                 ;
1081
;  IN:  bl = subfunction number                                   ;
1082
;       bh = device number                                        ;
1083
;       ecx, edx, .. depends on subfunction                       ;
1084
;                                                                 ;
1085
; OUT:  depends on subfunction                                    ;
1086
;                                                                 ;
1087
;-----------------------------------------------------------------;
3545 hidnplayr 1088
align 4
6011 hidnplayr 1089
ipv4_api:
3545 hidnplayr 1090
 
1091
        movzx   eax, bh
1092
        shl     eax, 2
1093
 
1094
        and     ebx, 0x000000ff
1095
        cmp     ebx, .number
1096
        ja      .error
1097
        jmp     dword [.table + 4*ebx]
1098
 
1099
  .table:
1100
        dd      .packets_tx     ; 0
1101
        dd      .packets_rx     ; 1
1102
        dd      .read_ip        ; 2
1103
        dd      .write_ip       ; 3
1104
        dd      .read_dns       ; 4
1105
        dd      .write_dns      ; 5
1106
        dd      .read_subnet    ; 6
1107
        dd      .write_subnet   ; 7
1108
        dd      .read_gateway   ; 8
1109
        dd      .write_gateway  ; 9
1110
  .number = ($ - .table) / 4 - 1
1111
 
1112
  .error:
1113
        mov     eax, -1
1114
        ret
1115
 
1116
  .packets_tx:
4052 hidnplayr 1117
        mov     eax, [IPv4_packets_tx + eax]
3545 hidnplayr 1118
        ret
1119
 
1120
  .packets_rx:
4052 hidnplayr 1121
        mov     eax, [IPv4_packets_rx + eax]
3545 hidnplayr 1122
        ret
1123
 
1124
  .read_ip:
7678 hidnplayr 1125
        mov     eax, [IPv4_address + eax]
3545 hidnplayr 1126
        ret
1127
 
1128
  .write_ip:
7678 hidnplayr 1129
        mov     [IPv4_address + eax], ecx
3545 hidnplayr 1130
        mov     edi, eax                        ; device number, we'll need it for ARP
1131
 
1132
        ; pre-calculate the local broadcast address
7678 hidnplayr 1133
        mov     ebx, [IPv4_subnet + eax]
3545 hidnplayr 1134
        not     ebx
1135
        or      ebx, ecx
7678 hidnplayr 1136
        mov     [IPv4_broadcast + eax], ebx
3545 hidnplayr 1137
 
7679 hidnplayr 1138
        mov     ebx, [net_device_list + eax]
7678 hidnplayr 1139
        mov     eax, [IPv4_address + eax]
6011 hidnplayr 1140
        call    arp_output_request              ; now send a gratuitous ARP
3545 hidnplayr 1141
 
6011 hidnplayr 1142
        call    net_send_event
3545 hidnplayr 1143
        xor     eax, eax
1144
        ret
1145
 
1146
  .read_dns:
7678 hidnplayr 1147
        mov     eax, [IPv4_nameserver + eax]
3545 hidnplayr 1148
        ret
1149
 
1150
  .write_dns:
7678 hidnplayr 1151
        mov     [IPv4_nameserver + eax], ecx
6011 hidnplayr 1152
        call    net_send_event
3545 hidnplayr 1153
        xor     eax, eax
1154
        ret
1155
 
1156
  .read_subnet:
7678 hidnplayr 1157
        mov     eax, [IPv4_subnet + eax]
3545 hidnplayr 1158
        ret
1159
 
1160
  .write_subnet:
7678 hidnplayr 1161
        mov     [IPv4_subnet + eax], ecx
3545 hidnplayr 1162
 
1163
        ; pre-calculate the local broadcast address
7678 hidnplayr 1164
        mov     ebx, [IPv4_address + eax]
3545 hidnplayr 1165
        not     ecx
1166
        or      ecx, ebx
7678 hidnplayr 1167
        mov     [IPv4_broadcast + eax], ecx
3545 hidnplayr 1168
 
6011 hidnplayr 1169
        call    net_send_event
3545 hidnplayr 1170
        xor     eax, eax
1171
        ret
1172
 
1173
  .read_gateway:
7678 hidnplayr 1174
        mov     eax, [IPv4_gateway + eax]
3545 hidnplayr 1175
        ret
1176
 
1177
  .write_gateway:
7678 hidnplayr 1178
        mov     [IPv4_gateway + eax], ecx
3545 hidnplayr 1179
 
6011 hidnplayr 1180
        call    net_send_event
3545 hidnplayr 1181
        xor     eax, eax
9799 Boppan 1182
        ret