Subversion Repositories Kolibri OS

Rev

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

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