Subversion Repositories Kolibri OS

Rev

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