Subversion Repositories Kolibri OS

Rev

Rev 1529 | 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: 1530 $
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
 
1530 hidnplayr 57
align 4
58
uglobal
1529 hidnplayr 59
 
1530 hidnplayr 60
	IP_LIST 	rd  MAX_IP
61
	SUBNET_LIST	rd  MAX_IP
62
	DNS_LIST	rd  MAX_IP
63
	GATEWAY_LIST	rd  MAX_IP
1529 hidnplayr 64
 
1530 hidnplayr 65
	IP_PACKETS_TX	rd  MAX_IP
66
	IP_PACKETS_RX	rd  MAX_IP
67
 
68
	FRAGMENT_LIST	rb  MAX_FRAGMENTS*FRAGMENT_slot.size
69
endg
70
 
71
 
72
;-----------------------------------------------------------------
73
;
74
; IPv4_init
75
;
76
;  This function resets all IP variables
77
;
78
;-----------------------------------------------------------------
79
macro	IPv4_init {
80
 
81
	xor	eax, eax
82
	mov	edi, IP_LIST
83
	mov	ecx, 4*MAX_IP
84
	rep	stosd
85
 
86
	mov	edi, FRAGMENT_LIST
87
	mov	ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
88
	rep	stosd
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
101
 
102
	mov	esi, FRAGMENT_LIST
103
	mov	ecx, MAX_FRAGMENTS
104
  .loop:
105
	cmp	[esi + FRAGMENT_slot.ttl], 0
106
	je	.try_next
107
	dec	[esi + FRAGMENT_slot.ttl]
108
	jnz	.try_next
109
	DEBUGF 1,"Fragment slot timed-out!\n"
110
;;; TODO: clear all entry's of timed-out slot
111
  .try_next:
112
	add	esi, 4
113
	loop	.loop
114
}
115
 
116
 
117
 
1529 hidnplayr 118
macro IPv4_checksum ptr {
119
 
120
; This is the fast procedure to create or check a IP header without options
121
; To create a new checksum, the checksum field must be set to 0 before computation
122
; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
123
 
124
	push	ebx
125
	xor	ebx, ebx
126
	add	bl, [ptr+1]
127
	adc	bh, [ptr+0]
128
 
129
	adc	bl, [ptr+3]
130
	adc	bh, [ptr+2]
131
 
132
	adc	bl, [ptr+5]
133
	adc	bh, [ptr+4]
134
 
135
	adc	bl, [ptr+7]
136
	adc	bh, [ptr+6]
137
 
138
	adc	bl, [ptr+9]
139
	adc	bh, [ptr+8]
140
 
141
; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
142
 
143
	adc	bl, [ptr+13]
144
	adc	bh, [ptr+12]
145
 
146
	adc	bl, [ptr+15]
147
	adc	bh, [ptr+14]
148
 
149
	adc	bl, [ptr+17]
150
	adc	bh, [ptr+16]
151
 
152
	adc	bl, [ptr+19]
153
	adc	bh, [ptr+18]
154
 
155
	adc	ebx, 0
156
 
157
	push	ecx
158
	mov	ecx, ebx
159
	shr	ecx, 16
160
	and	ebx, 0xffff
161
	add	ebx, ecx
162
 
163
	mov	ecx, ebx
164
	shr	ecx, 16
165
	add	ebx, ecx
166
 
167
	not	bx
168
	jnz	.not_zero
169
	dec	bx
170
  .not_zero:
171
	xchg	bl, bh
172
	pop	ecx
173
 
174
	neg	word [ptr+10]		; zero will stay zero so we just get the checksum
175
	add	word [ptr+10], bx	;  , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
176
	pop	ebx
177
 
178
}
179
 
180
 
181
 
1159 hidnplayr 182
;-----------------------------------------------------------------
183
;
1529 hidnplayr 184
; IPv4_input:
1159 hidnplayr 185
;
1249 hidnplayr 186
;  Will check if IP Packet isnt damaged
1159 hidnplayr 187
;  and call appropriate handler. (TCP/UDP/ICMP/..)
188
;
189
;  It will also re-construct fragmented packets
190
;
191
;  IN:  Pointer to buffer in [esp]
192
;       size of buffer in [esp+4]
193
;       pointer to device struct in ebx
194
;       pointer to IP Packet data in edx
195
;  OUT: /
196
;
197
;-----------------------------------------------------------------
198
align 4
1529 hidnplayr 199
IPv4_input:	 ; TODO: implement handler for IP options
1514 hidnplayr 200
		 ; TODO2: add code for raw sockets
1159 hidnplayr 201
 
1514 hidnplayr 202
	DEBUGF	1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\
203
	[edx + IPv4_Packet.SourceAddress]:1,[edx + IPv4_Packet.SourceAddress + 1]:1,[edx + IPv4_Packet.SourceAddress + 2]:1,[edx + IPv4_Packet.SourceAddress + 3]:1
204
	DEBUGF	1,"to: %u.%u.%u.%u\n",\
205
	[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 206
 
1473 hidnplayr 207
;-------------------------------------------
208
; Check if the packet still has time to live
1159 hidnplayr 209
 
1473 hidnplayr 210
	cmp	byte [edx + IPv4_Packet.TimeToLive], 0
211
	je	.dump
212
 
213
;--------------------------------------
214
; First, check if IP packet has options
215
 
216
	movzx	eax, [edx + IPv4_Packet.VersionAndIHL]
217
	and	al , 0x0f					; get IHL(header length)
218
	cmp	al , 0x05					; IHL!= 5*4(20 bytes)
219
	jnz	.has_options
220
 
221
;-------------------------------
1514 hidnplayr 222
; Now, re-calculate the checksum
1473 hidnplayr 223
 
1529 hidnplayr 224
	IPv4_checksum edx
225
	jnz	.dump						; if checksum isn't valid then dump packet
1249 hidnplayr 226
 
1473 hidnplayr 227
	DEBUGF	1,"IPv4 Checksum is correct\n"
1254 hidnplayr 228
 
1514 hidnplayr 229
;-----------------------------------
230
; Check if destination IP is correct
1473 hidnplayr 231
 
1514 hidnplayr 232
	call	NET_ptr_to_num
233
	shl	edi, 2
1473 hidnplayr 234
 
1514 hidnplayr 235
	; check if it matches local ip
1473 hidnplayr 236
 
1514 hidnplayr 237
	mov	eax, dword[IP_LIST+edi]
238
	cmp	[edx + IPv4_Packet.DestinationAddress], eax
239
	je	.ip_ok
1159 hidnplayr 240
 
1514 hidnplayr 241
	; check for broadcast
242
 
243
	mov	eax, dword[SUBNET_LIST+edi]
1159 hidnplayr 244
	not	eax
1514 hidnplayr 245
	or	eax, dword[IP_LIST+edi]
246
	cmp	[edx + IPv4_Packet.DestinationAddress], eax
247
	je	.ip_ok
1159 hidnplayr 248
 
1514 hidnplayr 249
	; or a special broadcast
1159 hidnplayr 250
 
1514 hidnplayr 251
	cmp	[edx + IPv4_Packet.DestinationAddress], -1
252
	je	.ip_ok
1473 hidnplayr 253
 
1519 hidnplayr 254
	; maybe it's a multicast then
255
 
256
	mov	eax, [edx + IPv4_Packet.DestinationAddress]
257
	and	eax, 0xff000000
1514 hidnplayr 258
;        cmp     eax, 224 shl 24
259
;        je      .ip_ok
1159 hidnplayr 260
 
1514 hidnplayr 261
	; or a loopback address
1473 hidnplayr 262
 
1514 hidnplayr 263
	cmp	eax, 127 shl 24
264
	je	.ip_ok
1473 hidnplayr 265
 
1514 hidnplayr 266
	; or it's not meant for us..
1159 hidnplayr 267
 
1514 hidnplayr 268
	DEBUGF	2,"Destination address does not match!\n"
269
	jmp	.dump
1159 hidnplayr 270
 
1514 hidnplayr 271
;------------------------
272
; Now we can update stats
1159 hidnplayr 273
 
1514 hidnplayr 274
  .ip_ok:
275
	inc	[IP_PACKETS_RX+edi]
1159 hidnplayr 276
 
1473 hidnplayr 277
;----------------------------------
278
; Check if the packet is fragmented
1159 hidnplayr 279
 
1473 hidnplayr 280
	test	[edx + IPv4_Packet.FlagsAndFragmentOffset], 1 shl 5	; Is 'more fragments' flag set ?
281
	jnz	.has_fragments						; If so, we definately have a fragmented packet
1159 hidnplayr 282
 
1473 hidnplayr 283
	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
284
	jnz	.is_last_fragment
285
 
286
;-------------------------------------------------------------------
287
; No, it's just a regular IP packet, pass it to the higher protocols
288
 
289
  .handle_it:							; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
1159 hidnplayr 290
	movzx	eax, byte [edx + IPv4_Packet.VersionAndIHL]	; Calculate Header length by using IHL field
1514 hidnplayr 291
	and	eax, 0x0000000f 				;
1159 hidnplayr 292
	shl	eax, 2						;
293
	movzx	ecx, word [edx + IPv4_Packet.TotalLength]	; Calculate length of encapsulated Packet
294
	xchg	cl , ch 					;
295
	sub	ecx, eax					;
296
 
297
	add	eax, edx
298
	push	eax
1473 hidnplayr 299
 
300
	mov	esi, [edx + IPv4_Packet.SourceAddress]		; These values might be of interest to the higher protocols
301
	mov	edi, [edx + IPv4_Packet.DestinationAddress]	;
1159 hidnplayr 302
	mov	al , [edx + IPv4_Packet.Protocol]
303
	pop	edx						; Offset to data (tcp/udp/icmp/.. Packet)
304
 
305
	cmp	al , IP_PROTO_TCP
1514 hidnplayr 306
	je	TCP_input
1159 hidnplayr 307
 
308
	cmp	al , IP_PROTO_UDP
1514 hidnplayr 309
	je	UDP_input
1159 hidnplayr 310
 
311
	cmp	al , IP_PROTO_ICMP
1514 hidnplayr 312
	je	ICMP_input
1159 hidnplayr 313
 
1473 hidnplayr 314
	DEBUGF	2,"unknown Internet protocol: %u\n", al
1159 hidnplayr 315
 
316
  .dump:
1473 hidnplayr 317
	DEBUGF	2,"IP_Handler - dumping\n"
1159 hidnplayr 318
;        inc     [dumped_rx_count]
319
	call	kernel_free
320
	add	esp, 4						; pop (balance stack)
321
	ret
322
 
323
 
1473 hidnplayr 324
;---------------------------
325
; Fragmented packet handler
326
 
327
 
328
  .has_fragments:
329
	movzx	eax, [edx + IPv4_Packet.FlagsAndFragmentOffset]
330
	xchg	al , ah
1159 hidnplayr 331
	shl	ax , 3
1473 hidnplayr 332
 
1159 hidnplayr 333
	DEBUGF	1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_Packet.Identification]:4
334
 
335
	test	ax , ax 					; Is this the first packet of the fragment?
1473 hidnplayr 336
	jz	.is_first_fragment
1159 hidnplayr 337
 
1473 hidnplayr 338
 
339
;-------------------------------------------------------
340
; We have a fragmented IP packet, but it's not the first
341
 
342
	DEBUGF	1,"Middle fragmented packet received!\n"
343
 
344
	call	IPv4_find_fragment_slot
345
	cmp	esi, -1
346
	je	.dump
347
 
348
	mov	word [esi + FRAGMENT_slot.ttl], 15		; Reset the ttl
349
	mov	esi, [esi + FRAGMENT_slot.ptr]
350
	or	edi, -1
351
  .find_last_entry:						; The following routine will try to find the last entry
352
	cmp	edi, [esi + FRAGMENT_entry.PrevPtr]
353
	jne	.destroy_slot					; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
354
	mov	edi, esi
355
	mov	esi, [esi + FRAGMENT_entry.NextPtr]
356
	cmp	esi, -1
357
	jne	.find_last_entry
358
								; We found the last entry (pointer is now in edi)
359
								; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
360
 
361
	pop	eax						; pointer to packet
362
	mov	[edi + FRAGMENT_entry.NextPtr], eax		; update pointer of previous entry to the new entry
363
	mov	[eax + FRAGMENT_entry.NextPtr], -1
364
	mov	[eax + FRAGMENT_entry.PrevPtr], edi
365
	mov	[eax + FRAGMENT_entry.Owner], ebx
366
 
367
	add	esp, 4
368
	ret
369
 
370
 
371
;------------------------------------
372
; We have received the first fragment
373
 
374
  .is_first_fragment:
1159 hidnplayr 375
	DEBUGF	1,"First fragmented packet received!\n"
376
								; try to locate a free slot..
377
	mov	ecx, MAX_FRAGMENTS
378
	mov	esi, FRAGMENT_LIST
1473 hidnplayr 379
  .find_free_slot:
1159 hidnplayr 380
	cmp	word [esi + FRAGMENT_slot.ttl], 0
381
	je	.found_free_slot
382
	add	esi, FRAGMENT_slot.size
383
	loop	.find_free_slot
384
	jmp	.dump						; If no free slot was found, dump the packet
385
 
1473 hidnplayr 386
  .found_free_slot:						; We found a free slot, let's fill in the FRAGMENT_slot structure
1159 hidnplayr 387
	mov	word [esi + FRAGMENT_slot.ttl], 15		; RFC recommends 15 secs as ttl
388
	mov	ax , word [edx + IPv4_Packet.Identification]
389
	mov	word [esi + FRAGMENT_slot.id], ax
390
	mov	eax, dword [edx + IPv4_Packet.SourceAddress]
391
	mov	dword [esi + FRAGMENT_slot.SrcIP], eax
392
	mov	eax, dword [edx + IPv4_Packet.DestinationAddress]
393
	mov	dword [esi + FRAGMENT_slot.DstIP], eax
394
	pop	eax
395
	mov	dword [esi + FRAGMENT_slot.ptr], eax
396
								; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
397
	mov	[eax + FRAGMENT_entry.NextPtr], -1
398
	mov	[eax + FRAGMENT_entry.PrevPtr], -1
399
	mov	[eax + FRAGMENT_entry.Owner], ebx
400
 
401
	add	esp, 4						; balance stack and exit
402
	ret
403
 
404
 
1473 hidnplayr 405
;-----------------------------------
406
; We have received the last fragment
1159 hidnplayr 407
 
1473 hidnplayr 408
  .is_last_fragment:
409
	DEBUGF	1,"Last fragmented packet received!\n"
1159 hidnplayr 410
 
1473 hidnplayr 411
	call	IPv4_find_fragment_slot
1159 hidnplayr 412
	cmp	esi, -1
413
	je	.dump
414
 
415
	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
416
	push	esi
1473 hidnplayr 417
	xor	eax, eax
1159 hidnplayr 418
	or	edi, -1
1473 hidnplayr 419
 
420
  .count_bytes:
1159 hidnplayr 421
	cmp	[esi + FRAGMENT_entry.PrevPtr], edi
1473 hidnplayr 422
	jne	.destroy_slot_pop						  ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
1159 hidnplayr 423
	mov	cx, word [esi + FRAGMENT_entry.Data + IPv4_Packet.TotalLength]	  ; Add total length
424
	xchg	cl, ch
425
	DEBUGF	1,"Packet size: %u\n", cx
426
	add	ax, cx
427
	movzx	cx, byte [esi + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]  ; Sub Header length
428
	and	cx, 0x000F
429
	shl	cx, 2
430
	DEBUGF	1,"Header size: %u\n", cx
431
	sub	ax, cx
432
	mov	edi, esi
433
	mov	esi, [esi + FRAGMENT_entry.NextPtr]
434
	cmp	esi, -1
435
	jne	.count_bytes
436
 
1514 hidnplayr 437
	mov	esi, [esp+4]
1159 hidnplayr 438
	mov	[edi + FRAGMENT_entry.NextPtr], esi			       ; Add this packet to the chain, this simplifies the following code
439
	mov	[esi + FRAGMENT_entry.NextPtr], -1
440
	mov	[esi + FRAGMENT_entry.PrevPtr], edi
441
	mov	[esi + FRAGMENT_entry.Owner], ebx
442
 
443
	mov	cx, [edx + IPv4_Packet.TotalLength]			       ; Note: This time we dont substract Header length
444
	xchg	cl , ch
445
	DEBUGF	1,"Packet size: %u\n", cx
446
	add	ax , cx
447
	DEBUGF	1,"Total Received data size: %u\n", eax
448
 
449
	push	eax
450
	mov	ax , [edx + IPv4_Packet.FlagsAndFragmentOffset]
451
	xchg	al , ah
452
	shl	ax , 3
453
	add	cx , ax
454
	pop	eax
455
	DEBUGF	1,"Total Fragment size: %u\n", ecx
456
 
457
	cmp	ax, cx
458
	jne	.destroy_slot_pop
459
 
460
	push	eax
461
	push	eax
462
	call	kernel_alloc
463
	test	eax, eax
464
	je	.destroy_slot_pop							; If we dont have enough space to allocate the buffer, discard all packets in slot
465
	mov	edx, [esp+4]								; Get pointer to first fragment entry back in edx
466
 
1473 hidnplayr 467
  .rebuild_packet_loop:
1159 hidnplayr 468
	movzx	ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.FlagsAndFragmentOffset]	; Calculate the fragment offset
1473 hidnplayr 469
	xchg	cl , ch 									;  intel byte order
1159 hidnplayr 470
	shl	cx , 3										;   multiply by 8 and clear first 3 bits
471
	DEBUGF	1,"Fragment offset: %u\n", cx
472
 
473
	lea	edi, [eax + ecx]								; Notice that edi will be equal to eax for first fragment
474
	movzx	ebx, byte [edx + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]		; Find header size (in ebx) of fragment
475
	and	bx , 0x000F									;
476
	shl	bx , 2										;
477
 
478
	lea	esi, [edx + FRAGMENT_entry.Data]						; Set esi to the correct begin of fragment
479
	movzx	ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.TotalLength] 		; Calculate total length of fragment
480
	xchg	cl, ch										;  intel byte order
481
 
482
	cmp	edi, eax									; Is this packet the first fragment ?
483
	je	.first_fragment
484
	sub	cx, bx										; If not, dont copy the header
485
	add	esi, ebx									;
1473 hidnplayr 486
  .first_fragment:
1159 hidnplayr 487
 
488
	push	cx										; First copy dword-wise, then byte-wise
489
	shr	cx, 2										;
490
	rep	movsd										;
491
	pop	cx										;
492
	and	cx, 3										;
493
	rep	movsb										;
494
 
495
	push	eax
496
	push	edx										; Push pointer to fragment onto stack
1473 hidnplayr 497
	mov	ebx, [edx + FRAGMENT_entry.Owner]						; we need to remeber the owner, in case this is the last packet
1159 hidnplayr 498
	mov	edx, [edx + FRAGMENT_entry.NextPtr]						; Set edx to the next pointer
499
	call	kernel_free									; free the previous fragment buffer (this uses the value from stack)
500
	pop	eax
501
	cmp	edx, -1 									; Check if it is last fragment in chain
502
	jne	.rebuild_packet_loop
503
 
504
	pop	ecx										;
505
	xchg	cl, ch
506
	mov	edx, eax
507
	mov	word [edx + IPv4_Packet.TotalLength], cx
508
	add	esp, 8
509
 
1473 hidnplayr 510
	xchg	cl, ch		    ;
511
 
512
	push	ecx		   ;;;;
513
	push	eax		   ;;;;
514
 
515
;        mov     esi, edx           ;  This prints the IP packet to the debug board (usefull when using serial output debug..)
1159 hidnplayr 516
;                                   ;
1529 hidnplayr 517
;        packet_to_debug
1159 hidnplayr 518
 
1473 hidnplayr 519
	jmp	.handle_it	    ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
1249 hidnplayr 520
 
1473 hidnplayr 521
  .destroy_slot_pop:
522
	add	esp, 4
523
  .destroy_slot:
524
	DEBUGF	1,"Destroy fragment slot!\n"
525
	; TODO!
526
	jmp	.dump
1249 hidnplayr 527
 
528
 
1159 hidnplayr 529
 
530
 
1473 hidnplayr 531
;-----------------------------------
532
; The IP packet has some options
1159 hidnplayr 533
 
1473 hidnplayr 534
  .has_options:
535
	jmp	.dump
1159 hidnplayr 536
 
537
 
1166 hidnplayr 538
 
1159 hidnplayr 539
;-----------------------------------------------------------------
540
;
541
; find fragment slot
542
;
1514 hidnplayr 543
; IN: pointer to fragmented packet in edx
1159 hidnplayr 544
; OUT: pointer to slot in edi, -1 on error
545
;
546
;-----------------------------------------------------------------
1473 hidnplayr 547
align 4
548
IPv4_find_fragment_slot:
1159 hidnplayr 549
 
1514 hidnplayr 550
;;; TODO: the RFC says we should check protocol number too
551
 
1159 hidnplayr 552
	push	eax ebx ecx edx
553
	mov	ax , word [edx + IPv4_Packet.Identification]
554
	mov	ecx, MAX_FRAGMENTS
555
	mov	esi, FRAGMENT_LIST
556
	mov	ebx, dword [edx + IPv4_Packet.SourceAddress]
557
	mov	edx, dword [edx + IPv4_Packet.DestinationAddress]
558
  .find_slot:
559
	cmp	word [esi + FRAGMENT_slot.id], ax
560
	jne	.try_next
561
	cmp	dword [esi + FRAGMENT_slot.SrcIP], ebx
562
	jne	.try_next
563
	cmp	dword [esi + FRAGMENT_slot.DstIP], edx
564
	je	.found_slot
565
  .try_next:
566
	add	esi, FRAGMENT_slot.size
567
	loop	.find_slot
1473 hidnplayr 568
;        pop     edx ebx
1159 hidnplayr 569
	or	esi, -1
570
;        ret
571
 
572
  .found_slot:
573
	pop	edx ecx ebx eax
574
	ret
575
 
576
 
1514 hidnplayr 577
;------------------------------------------------------------------
1159 hidnplayr 578
;
1529 hidnplayr 579
; IPv4_output
1514 hidnplayr 580
;
1159 hidnplayr 581
; IN: eax = dest ip
582
;     ebx = source ip
583
;     ecx = data length
1529 hidnplayr 584
;     dx  = fragment id
585
;     di  = TTL shl 8 + protocol
1159 hidnplayr 586
;
1249 hidnplayr 587
; OUT: eax = pointer to buffer start
588
;      ebx = pointer to device struct (needed for sending procedure)
1159 hidnplayr 589
;      ecx = unchanged (packet size of embedded data)
1249 hidnplayr 590
;      edx = size of complete buffer
1514 hidnplayr 591
;      edi = pointer to start of data (0 on error)
1159 hidnplayr 592
;
1514 hidnplayr 593
;------------------------------------------------------------------
1159 hidnplayr 594
align 4
1529 hidnplayr 595
IPv4_output:
1159 hidnplayr 596
 
1529 hidnplayr 597
	DEBUGF 1,"IPv4_create_packet: size=%u\n", ecx
1159 hidnplayr 598
 
1529 hidnplayr 599
	cmp	ecx, 65500		; Max IPv4 packet size
600
	jg	.too_large
1159 hidnplayr 601
 
1206 hidnplayr 602
	push	ecx eax ebx dx di
603
 
1196 hidnplayr 604
	call	ARP_IP_to_MAC
1159 hidnplayr 605
 
1529 hidnplayr 606
	test	eax, 0xffff0000 	; error bits
607
	jnz	.arp_error
1196 hidnplayr 608
 
1530 hidnplayr 609
  .continue:
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