Subversion Repositories Kolibri OS

Rev

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