Subversion Repositories Kolibri OS

Rev

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

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