Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3555 Serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3908 Serge 3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
3555 Serge 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
 
4265 Serge 21
IPv4_MAX_FRAGMENTS              = 64
3555 Serge 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
 
4265 Serge 38
struct  IPv4_FRAGMENT_slot
3555 Serge 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
 
4265 Serge 48
struct  IPv4_FRAGMENT_entry             ; This structure will replace the ethernet header in fragmented ip packets
3555 Serge 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
 
3725 Serge 58
uglobal
3555 Serge 59
align 4
60
 
3626 Serge 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
3555 Serge 66
 
4265 Serge 67
        IPv4_packets_tx         rd NET_DEVICES_MAX
68
        IPv4_packets_rx         rd NET_DEVICES_MAX
69
        IPv4_packets_dumped     rd NET_DEVICES_MAX
3555 Serge 70
 
4265 Serge 71
        IPv4_FRAGMENT_LIST      rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
3725 Serge 72
 
3555 Serge 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
4265 Serge 87
        mov     ecx, 7*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_MAX_FRAGMENTS)/4
3725 Serge 88
        rep stosd
3555 Serge 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
 
4265 Serge 102
        mov     esi, IPv4_FRAGMENT_LIST
103
        mov     ecx, IPv4_MAX_FRAGMENTS
3555 Serge 104
  .loop:
4265 Serge 105
        cmp     [esi + IPv4_FRAGMENT_slot.ttl], 0
3555 Serge 106
        je      .next
4265 Serge 107
        dec     [esi + IPv4_FRAGMENT_slot.ttl]
3555 Serge 108
        jz      .died
109
  .next:
4265 Serge 110
        add     esi, sizeof.IPv4_FRAGMENT_slot
3555 Serge 111
        dec     ecx
112
        jnz     .loop
113
        jmp     .done
114
 
115
  .died:
3589 Serge 116
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4 Fragment slot timed-out!\n"
3555 Serge 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
 
3589 Serge 209
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input, packet from: %u.%u.%u.%u ",\
3555 Serge 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
3589 Serge 212
        DEBUGF  DEBUG_NETWORK_VERBOSE, "to: %u.%u.%u.%u\n",\
3555 Serge 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
 
3589 Serge 222
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Checksum ok\n"
3555 Serge 223
 
224
;-----------------------------------
225
; Check if destination IP is correct
226
 
3725 Serge 227
        call    NET_ptr_to_num4
3555 Serge 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
 
3589 Serge 259
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destination address does not match!\n"
3555 Serge 260
        jmp     .dump
261
 
262
;------------------------
263
; Now we can update stats
264
 
265
  .ip_ok:
4265 Serge 266
        inc     [IPv4_packets_rx + edi]
3555 Serge 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
 
3589 Serge 303
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: unknown protocol %u\n", al
3555 Serge 304
 
305
  .dump:
3589 Serge 306
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n"
4265 Serge 307
        inc     [IPv4_packets_dumped]                           ; FIXME: use correct interface
3908 Serge 308
        call    NET_packet_free
3555 Serge 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
 
4265 Serge 322
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx
3555 Serge 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
 
3589 Serge 331
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Middle fragment packet received!\n"
3555 Serge 332
 
333
        call    IPv4_find_fragment_slot
334
        cmp     esi, -1
335
        je      .dump
336
 
4265 Serge 337
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; Reset the ttl
338
        mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]
3555 Serge 339
        or      edi, -1
340
  .find_last_entry:                                             ; The following routine will try to find the last entry
4265 Serge 341
        cmp     edi, [esi + IPv4_FRAGMENT_entry.PrevPtr]
3555 Serge 342
        jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
343
        mov     edi, esi
4265 Serge 344
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3555 Serge 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
4265 Serge 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
3555 Serge 355
 
356
        add     esp, 4
357
        ret
358
 
359
 
360
;------------------------------------
361
; We have received the first fragment
362
 
363
  .is_first_fragment:
3589 Serge 364
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n"
3555 Serge 365
                                                                ; try to locate a free slot..
4265 Serge 366
        mov     ecx, IPv4_MAX_FRAGMENTS
367
        mov     esi, IPv4_FRAGMENT_LIST
3555 Serge 368
  .find_free_slot:
4265 Serge 369
        cmp     word [esi + IPv4_FRAGMENT_slot.ttl], 0
3555 Serge 370
        je      .found_free_slot
4265 Serge 371
        add     esi, sizeof.IPv4_FRAGMENT_slot
3555 Serge 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
4265 Serge 376
        mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
3555 Serge 377
        mov     ax, [edx + IPv4_header.Identification]
4265 Serge 378
        mov     [esi + IPv4_FRAGMENT_slot.id], ax
3555 Serge 379
        mov     eax, [edx + IPv4_header.SourceAddress]
4265 Serge 380
        mov     [esi + IPv4_FRAGMENT_slot.SrcIP], eax
3555 Serge 381
        mov     eax, [edx + IPv4_header.DestinationAddress]
4265 Serge 382
        mov     [esi + IPv4_FRAGMENT_slot.DstIP], eax
3555 Serge 383
        pop     eax
4265 Serge 384
        mov     [esi + IPv4_FRAGMENT_slot.ptr], eax
3555 Serge 385
                                                                ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
4265 Serge 386
        mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
387
        mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], -1
388
        mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
3555 Serge 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:
3589 Serge 398
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Last fragment packet received!\n"
3555 Serge 399
 
400
        call    IPv4_find_fragment_slot
401
        cmp     esi, -1
402
        je      .dump
403
 
4265 Serge 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
3555 Serge 405
        push    esi
406
        xor     eax, eax
407
        or      edi, -1
408
 
409
  .count_bytes:
4265 Serge 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
3555 Serge 413
        xchg    cl, ch
3589 Serge 414
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3555 Serge 415
        add     ax, cx
4265 Serge 416
        movzx   cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]      ; Sub Header length
3555 Serge 417
        and     cx, 0x000F
418
        shl     cx, 2
3589 Serge 419
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
3555 Serge 420
        sub     ax, cx
421
        mov     edi, esi
4265 Serge 422
        mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
3555 Serge 423
        cmp     esi, -1
424
        jne     .count_bytes
425
 
426
        mov     esi, [esp+4]
4265 Serge 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
3555 Serge 431
 
4265 Serge 432
        mov     cx, [edx + IPv4_header.TotalLength]                                     ; Note: This time we dont substract Header length
3555 Serge 433
        xchg    cl, ch
3589 Serge 434
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
3555 Serge 435
        add     ax, cx
3589 Serge 436
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
3555 Serge 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
3589 Serge 444
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
3555 Serge 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:
4265 Serge 457
        movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
3555 Serge 458
        xchg    cl, ch                                                                  ;  intel byte order
459
        shl     cx, 3                                                                   ;   multiply by 8 and clear first 3 bits
3589 Serge 460
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
3555 Serge 461
 
462
        lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
4265 Serge 463
        movzx   ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Find header size (in ebx) of fragment
3555 Serge 464
        and     bx, 0x000F                                                              ;
465
        shl     bx, 2                                                                   ;
466
 
4265 Serge 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
3555 Serge 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
 
4265 Serge 477
 
478
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
3555 Serge 479
        push    cx                                                                      ; First copy dword-wise, then byte-wise
480
        shr     cx, 2                                                                   ;
3725 Serge 481
        rep movsd                                                                       ;
3555 Serge 482
        pop     cx                                                                      ;
483
        and     cx, 3                                                                   ;
3725 Serge 484
        rep movsb                                                                       ;
3555 Serge 485
 
486
        push    eax
4265 Serge 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
3555 Serge 489
        push    edx                                                                     ; Push pointer to fragment onto stack
4265 Serge 490
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
3908 Serge 491
        call    NET_packet_free                                                         ; free the previous fragment buffer (this uses the value from stack)
4265 Serge 492
        pop     edx ebx eax
3555 Serge 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
4265 Serge 500
        add     esp, 12
3555 Serge 501
        xchg    cl, ch
4265 Serge 502
        push    ecx edx                 ; size and pointer
503
        jmp     .handle_it              ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
3555 Serge 504
 
505
  .destroy_slot_pop:
506
        add     esp, 4
507
  .destroy_slot:
3589 Serge 508
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
3555 Serge 509
        ; TODO!
510
        jmp     .dump
511
 
512
 
513
 
514
 
515
 
516
;-----------------------------------------------------------------
517
;
518
; find fragment slot
519
;
520
; IN: pointer to fragmented packet in edx
521
; OUT: pointer to slot in esi, -1 on error
522
;
523
;-----------------------------------------------------------------
524
align 4
525
IPv4_find_fragment_slot:
526
 
527
;;; TODO: the RFC says we should check protocol number too
528
 
529
        push    eax ebx ecx edx
530
        mov     ax, [edx + IPv4_header.Identification]
4265 Serge 531
        mov     ecx, IPv4_MAX_FRAGMENTS
532
        mov     esi, IPv4_FRAGMENT_LIST
3555 Serge 533
        mov     ebx, [edx + IPv4_header.SourceAddress]
534
        mov     edx, [edx + IPv4_header.DestinationAddress]
535
  .find_slot:
4265 Serge 536
        cmp     [esi + IPv4_FRAGMENT_slot.id], ax
3555 Serge 537
        jne     .try_next
4265 Serge 538
        cmp     [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
3555 Serge 539
        jne     .try_next
4265 Serge 540
        cmp     [esi + IPv4_FRAGMENT_slot.DstIP], edx
3555 Serge 541
        je      .found_slot
542
  .try_next:
4265 Serge 543
        add     esi, sizeof.IPv4_FRAGMENT_slot
3555 Serge 544
        loop    .find_slot
545
 
546
        or      esi, -1
547
  .found_slot:
548
        pop     edx ecx ebx eax
549
        ret
550
 
551
 
552
;------------------------------------------------------------------
553
;
554
; IPv4_output
555
;
4265 Serge 556
; IN:   eax = Destination IP
557
;       ecx = data length
558
;       edx = Source IP
559
;       di  = TTL shl 8 + protocol
3555 Serge 560
;
4265 Serge 561
; OUT:  eax = pointer to buffer start
562
;       ebx = pointer to device struct (needed for sending procedure)
563
;       ecx = unchanged (packet size of embedded data)
564
;       edx = size of complete buffer
565
;       edi = pointer to start of data (0 on error)
3555 Serge 566
;
567
;------------------------------------------------------------------
568
align 4
569
IPv4_output:
570
 
3626 Serge 571
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, eax
3555 Serge 572
 
573
        cmp     ecx, 65500              ; Max IPv4 packet size
574
        ja      .too_large
575
 
4265 Serge 576
        push    ecx di eax
577
        call    IPv4_route              ; outputs device number in edi, dest ip in eax, source IP in edx
578
        push    edx
3555 Serge 579
 
3626 Serge 580
        test    edi, edi
581
        jz      .loopback
582
 
3555 Serge 583
        call    ARP_IP_to_MAC
584
        test    eax, 0xffff0000         ; error bits
585
        jnz     .arp_error
586
        push    ebx                     ; push the mac onto the stack
587
        push    ax
588
 
4265 Serge 589
        inc     [IPv4_packets_tx + edi]   ; update stats
3555 Serge 590
 
3725 Serge 591
        mov     ebx, [NET_DRV_LIST + edi]
3555 Serge 592
        lea     eax, [ebx + ETH_DEVICE.mac]
593
        mov     edx, esp
4265 Serge 594
        mov     ecx, [esp + 6 + 8 + 2]
3555 Serge 595
        add     ecx, sizeof.IPv4_header
3626 Serge 596
        mov     di, ETHER_PROTO_IPv4
3555 Serge 597
        call    ETH_output
598
        jz      .eth_error
599
        add     esp, 6                  ; pop the mac out of the stack
600
 
601
  .continue:
602
        xchg    cl, ch                                  ; internet byte order
603
        mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
604
        mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
605
        mov     [edi + IPv4_header.TotalLength], cx
606
        mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
607
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
4265 Serge 608
 
3555 Serge 609
        mov     [edi + IPv4_header.HeaderChecksum], 0
610
        popd    [edi + IPv4_header.SourceAddress]
611
        popd    [edi + IPv4_header.DestinationAddress]
612
 
4265 Serge 613
        pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
614
;               [edi + IPv4_header.Protocol]
615
 
3555 Serge 616
        pop     ecx
617
 
618
        IPv4_checksum edi
619
        add     edi, sizeof.IPv4_header
3589 Serge 620
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
3555 Serge 621
        ret
622
 
623
  .eth_error:
3626 Serge 624
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
3555 Serge 625
        add     esp, 3*4+2+6
626
        xor     edi, edi
627
        ret
628
 
629
  .arp_error:
3626 Serge 630
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
3555 Serge 631
        add     esp, 3*4+2
632
        xor     edi, edi
633
        ret
634
 
635
  .too_large:
3589 Serge 636
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
3555 Serge 637
        xor     edi, edi
638
        ret
639
 
640
  .loopback:
3626 Serge 641
        mov     dword [esp + 2], eax            ; change source IP to dest IP
642
        mov     ecx, [esp + 10]
3555 Serge 643
        add     ecx, sizeof.IPv4_header
3626 Serge 644
        mov     edi, AF_INET4
3555 Serge 645
        call    LOOP_output
646
        jmp     .continue
647
 
648
 
649
 
650
 
651
;------------------------------------------------------------------
652
;
653
; IPv4_output_raw
654
;
655
; IN: eax = socket ptr
656
;     ecx = data length
657
;     esi = data ptr
658
;
659
; OUT: /
660
;
661
;------------------------------------------------------------------
662
align 4
663
IPv4_output_raw:
664
 
665
        DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
666
 
667
        cmp     ecx, 1480               ;;;;; FIXME
668
        ja      .too_large
669
 
670
        sub     esp, 8
671
        push    esi eax
672
 
673
        call    IPv4_route
674
        call    ARP_IP_to_MAC
675
 
676
        test    eax, 0xffff0000         ; error bits
677
        jnz     .arp_error
678
 
679
        push    ebx                     ; push the mac
680
        push    ax
681
 
4265 Serge 682
        inc     [IPv4_packets_tx + 4*edi]
3626 Serge 683
        mov     ebx, [NET_DRV_LIST + 4*edi]
3555 Serge 684
        lea     eax, [ebx + ETH_DEVICE.mac]
685
        mov     edx, esp
686
        mov     ecx, [esp + 6 + 4]
687
        add     ecx, sizeof.IPv4_header
3626 Serge 688
        mov     di, ETHER_PROTO_IPv4
3555 Serge 689
        call    ETH_output
690
        jz      .error
691
 
692
        add     esp, 6  ; pop the mac
693
 
694
        mov     dword[esp+4+4], edx
695
        mov     dword[esp+4+4+4], eax
696
 
697
        pop     eax esi
698
;; todo: check socket options if we should add header, or just compute checksum
699
 
700
        push    edi ecx
3725 Serge 701
        rep movsb
3555 Serge 702
        pop     ecx edi
703
 
704
;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
705
;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
706
;        [edi + IPv4_header.TotalLength]
707
;        [edi + IPv4_header.TotalLength]                ; internet byte order
708
;        [edi + IPv4_header.FlagsAndFragmentOffset]
709
 
710
        mov     [edi + IPv4_header.HeaderChecksum], 0
711
 
712
;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
713
;        [edi + IPv4_header.Protocol]
714
;        [edi + IPv4_header.Identification]             ; fragment id
715
;        [edi + IPv4_header.SourceAddress]
716
;        [edi + IPv4_header.DestinationAddress]
717
 
718
        IPv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
719
        add     edi, sizeof.IPv4_header
3589 Serge 720
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
3555 Serge 721
        call    [ebx + NET_DEVICE.transmit]
722
        ret
723
 
724
  .error:
725
        add     esp, 6
726
  .arp_error:
727
        add     esp, 8+4+4
728
  .too_large:
3589 Serge 729
        DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output_raw: Failed\n"
3555 Serge 730
        sub     edi, edi
731
        ret
732
 
733
 
734
;--------------------------------------------------------
735
;
736
;
737
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
738
;     dword [esp+4] = buffer size
739
;     esi = pointer to ip header in that buffer
740
;     ecx = max size of fragments
741
;
742
; OUT: /
743
;
744
;--------------------------------------------------------
745
 
746
align 4
747
IPv4_fragment:
748
 
3589 Serge 749
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
3555 Serge 750
 
751
        and     ecx, not 111b   ; align 4
752
 
753
        cmp     ecx, sizeof.IPv4_header + 8     ; must be able to put at least 8 bytes
754
        jb      .err2
755
 
756
        push    esi ecx
757
        mov     eax, [esi + IPv4_header.DestinationAddress]
758
        call    ARP_IP_to_MAC
759
        pop     ecx esi
760
        cmp     eax, -1
761
        jz      .err2
762
 
763
        push    ebx
764
        push    ax
765
 
766
        mov     ebx, [NET_DRV_LIST]
767
        lea     eax, [ebx + ETH_DEVICE.mac]
768
        push    eax
769
 
770
 
771
        push    esi                             ; ptr to ip header
772
        sub     ecx, sizeof.IPv4_header         ; substract header size
773
        push    ecx                             ; max data size
774
        push    dword 0                         ; offset
775
 
776
  .new_fragment:
3589 Serge 777
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
3555 Serge 778
 
779
 
780
        mov     eax, [esp + 3*4]
781
        lea     ebx, [esp + 4*4]
3626 Serge 782
        mov     di , ETHER_PROTO_IPv4
3555 Serge 783
        call    ETH_output
784
 
785
        cmp     edi, -1
786
        jz      .err
787
 
788
; copy header
789
        mov     esi, [esp + 2*4]
790
        mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
3725 Serge 791
        rep movsd
3555 Serge 792
 
793
; copy data
794
        mov     esi, [esp + 2*4]
795
        add     esi, sizeof.IPv4_header
796
        add     esi, [esp]      ; offset
797
 
798
        mov     ecx, [esp + 1*4]
3589 Serge 799
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_fragment: copying %u bytes\n", ecx
3725 Serge 800
        rep movsb
3555 Serge 801
 
802
; now, correct header
803
        mov     ecx, [esp + 1*4]
804
        add     ecx, sizeof.IPv4_header
805
        xchg    cl, ch
806
        mov     [edi + IPv4_header.TotalLength], cx
807
 
808
        mov     ecx, [esp]              ; offset
809
        xchg    cl, ch
810
 
811
;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
812
;        je      .last_fragment
813
        or      cx, 1 shl 2             ; more fragments
814
;  .last_fragment:
815
        mov     [edi + IPv4_header.FlagsAndFragmentOffset], cx
816
 
817
        mov     [edi + IPv4_header.HeaderChecksum], 0
818
 
819
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
820
        mov     ecx, [esp + 1*4]
821
 
822
        push    edx eax
823
        IPv4_checksum edi
824
 
825
        call    [ebx + NET_DEVICE.transmit]
826
        ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
827
 
3725 Serge 828
        mov     ecx, [esp+4]
3555 Serge 829
        add     [esp], ecx
830
 
831
        mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
832
        add     ecx, [esp+3*4+6+4+4]    ; buff size
833
        sub     ecx, [esp+2*4]          ; ptr to ip header
834
        add     ecx, [esp]              ; offset
835
 
3589 Serge 836
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: %u bytes remaining\n", ecx
3555 Serge 837
 
838
        cmp     ecx, [esp+1*4]
839
        jae     .new_fragment
840
 
841
        mov     [esp+4], ecx            ; set fragment size to remaining packet size
842
        jmp     .new_fragment
843
 
844
      .err:
3589 Serge 845
        DEBUGF  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
3555 Serge 846
      .done:
847
        add     esp, 12 + 4 + 6
848
      .err2:
3589 Serge 849
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: dumping\n"
3908 Serge 850
        call    NET_packet_free
3555 Serge 851
        add     esp, 4
852
 
853
        ret
854
 
855
 
856
 
857
;---------------------------------------------------------------------------
858
;
859
; IPv4_route
860
;
861
; IN:   eax = Destination IP
4265 Serge 862
;       edx = Source IP
863
; OUT:  eax = Destination IP (or gateway IP)
864
;       edx = Source IP
865
;       edi = device number*4
866
; DESTROYED:
867
;       ecx
3555 Serge 868
;
869
;---------------------------------------------------------------------------
870
align 4
4265 Serge 871
IPv4_route:     ; TODO: return error if no valid route found
3555 Serge 872
 
873
        cmp     eax, 0xffffffff
874
        je      .broadcast
875
 
876
        xor     edi, edi
877
  .loop:
4265 Serge 878
        mov     ebx, [IP_LIST + edi]
879
        and     ebx, [SUBNET_LIST + edi]
3555 Serge 880
        jz      .next
4265 Serge 881
        mov     ecx, eax
882
        and     ecx, [SUBNET_LIST + edi]
883
        cmp     ebx, ecx
884
        je      .got_it
3555 Serge 885
  .next:
886
        add     edi, 4
4265 Serge 887
        cmp     edi, 4*NET_DEVICES_MAX
888
        jb      .loop
3555 Serge 889
 
4265 Serge 890
        mov     eax, [GATEWAY_LIST + 4]         ; TODO: let user (or a user space daemon) configure default route
3555 Serge 891
  .broadcast:
4265 Serge 892
        mov     edi, 4                          ; TODO: same as above
893
  .got_it:
894
        DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
895
        test    edx, edx
896
        jnz     @f
897
        mov     edx, [IP_LIST + edi]
898
  @@:
899
 
3555 Serge 900
        ret
901
 
902
 
903
 
904
;---------------------------------------------------------------------------
905
;
906
; IPv4_get_frgmnt_num
907
;
908
; IN: /
909
; OUT: fragment number in ax
910
;
911
;---------------------------------------------------------------------------
912
align 4
913
IPv4_get_frgmnt_num:
914
        xor     ax, ax  ;;; TODO: replace this with real code
915
 
916
        ret
917
 
918
 
4265 Serge 919
;-----------------------------------------------------------------
920
;
921
; IPv4_connect
922
;
923
;   IN: eax = socket pointer
924
;  OUT: eax = 0 ok / -1 error
925
;       ebx = error code
926
;
927
;-------------------------
928
align 4
929
IPv4_connect:
930
 
931
        push    eax edx
932
        lea     ecx, [eax + SOCKET.mutex]
933
        call    mutex_lock
934
        pop     edx eax
935
 
936
; Fill in local IP
937
        cmp     [eax + IP_SOCKET.LocalIP], 0
938
        jne     @f
939
        push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
940
        pop     [eax + IP_SOCKET.LocalIP]
941
 
942
; Fill in remote IP
943
        pushd   [edx + 4]
944
        pop     [eax + IP_SOCKET.RemoteIP]
945
 
946
; Set up data receiving queue
947
        push    eax
948
        init_queue (eax + SOCKET_QUEUE_LOCATION)
949
        pop     eax
950
 
951
        lea     ecx, [eax + SOCKET.mutex]
952
        call    mutex_unlock
953
 
954
        xor     eax, eax
955
        ret
956
 
957
 
3555 Serge 958
;---------------------------------------------------------------------------
959
;
960
; IPv4_API
961
;
962
; This function is called by system function 75
963
;
964
; IN:  subfunction number in bl
965
;      device number in bh
966
;      ecx, edx, .. depends on subfunction
967
;
968
; OUT:
969
;
970
;---------------------------------------------------------------------------
971
align 4
972
IPv4_api:
973
 
974
        movzx   eax, bh
975
        shl     eax, 2
976
 
977
        and     ebx, 0x000000ff
978
        cmp     ebx, .number
979
        ja      .error
980
        jmp     dword [.table + 4*ebx]
981
 
982
  .table:
983
        dd      .packets_tx     ; 0
984
        dd      .packets_rx     ; 1
985
        dd      .read_ip        ; 2
986
        dd      .write_ip       ; 3
987
        dd      .read_dns       ; 4
988
        dd      .write_dns      ; 5
989
        dd      .read_subnet    ; 6
990
        dd      .write_subnet   ; 7
991
        dd      .read_gateway   ; 8
992
        dd      .write_gateway  ; 9
993
  .number = ($ - .table) / 4 - 1
994
 
995
  .error:
996
        mov     eax, -1
997
        ret
998
 
999
  .packets_tx:
4265 Serge 1000
        mov     eax, [IPv4_packets_tx + eax]
3555 Serge 1001
        ret
1002
 
1003
  .packets_rx:
4265 Serge 1004
        mov     eax, [IPv4_packets_rx + eax]
3555 Serge 1005
        ret
1006
 
1007
  .read_ip:
1008
        mov     eax, [IP_LIST + eax]
1009
        ret
1010
 
1011
  .write_ip:
1012
        mov     [IP_LIST + eax], ecx
1013
        mov     edi, eax                        ; device number, we'll need it for ARP
1014
 
1015
        ; pre-calculate the local broadcast address
1016
        mov     ebx, [SUBNET_LIST + eax]
1017
        not     ebx
1018
        or      ebx, ecx
1019
        mov     [BROADCAST_LIST + eax], ebx
1020
 
3626 Serge 1021
        mov     ebx, [NET_DRV_LIST + eax]
1022
        mov     eax, [IP_LIST + eax]
3555 Serge 1023
        call    ARP_output_request              ; now send a gratuitous ARP
1024
 
1025
        call    NET_send_event
1026
        xor     eax, eax
1027
        ret
1028
 
1029
  .read_dns:
1030
        mov     eax, [DNS_LIST + eax]
1031
        ret
1032
 
1033
  .write_dns:
1034
        mov     [DNS_LIST + eax], ecx
1035
        call    NET_send_event
1036
        xor     eax, eax
1037
        ret
1038
 
1039
  .read_subnet:
1040
        mov     eax, [SUBNET_LIST + eax]
1041
        ret
1042
 
1043
  .write_subnet:
1044
        mov     [SUBNET_LIST + eax], ecx
1045
 
1046
        ; pre-calculate the local broadcast address
1047
        mov     ebx, [IP_LIST + eax]
1048
        not     ecx
1049
        or      ecx, ebx
1050
        mov     [BROADCAST_LIST + eax], ecx
1051
 
1052
        call    NET_send_event
1053
        xor     eax, eax
1054
        ret
1055
 
1056
  .read_gateway:
1057
        mov     eax, [GATEWAY_LIST + eax]
1058
        ret
1059
 
1060
  .write_gateway:
1061
        mov     [GATEWAY_LIST + eax], ecx
1062
 
1063
        call    NET_send_event
1064
        xor     eax, eax
1065
        ret