Subversion Repositories Kolibri OS

Rev

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