Subversion Repositories Kolibri OS

Rev

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