Subversion Repositories Kolibri OS

Rev

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

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