Subversion Repositories Kolibri OS

Rev

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

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