Subversion Repositories Kolibri OS

Rev

Rev 4053 | Rev 4259 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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