Subversion Repositories Kolibri OS

Rev

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

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