Subversion Repositories Kolibri OS

Rev

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