Subversion Repositories Kolibri OS

Rev

Rev 1541 | 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: 1838 $
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
 
1838 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
 
1541 hidnplayr 656
 
657
 
658
 
659
;------------------------------------------------------------------
660
;
661
; IPv4_output_raw
662
;
663
; IN: eax = socket ptr
664
;     ecx = data length
665
;     esi = data ptr
666
;
667
; OUT: /
668
;
669
;------------------------------------------------------------------
670
align 4
671
IPv4_output_raw:
672
 
673
	DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
674
 
675
	cmp	ecx, 1480		;;;;;
676
	jg	.too_large
677
 
678
	sub	esp, 8
679
	push	esi eax
680
 
681
	call	ARP_IP_to_MAC
682
 
683
	test	eax, 0xffff0000 	; error bits
684
	jnz	.arp_error
685
 
686
  .continue:
687
 
688
	push	ebx	; push the mac
689
	push	ax
690
 
691
	call	IPv4_dest_to_dev
692
	inc	[IP_PACKETS_TX+edi]
693
	mov	ebx, [NET_DRV_LIST+edi]
694
	lea	eax, [ebx + ETH_DEVICE.mac]
695
	mov	edx, esp
696
	mov	ecx, [esp + 6+4]
697
	add	ecx, IPv4_Packet.DataOrOptional
698
	mov	di, ETHER_IPv4
699
	call	ETH_output
700
	jz	.error
701
 
702
	add	esp, 6	; pop the mac
703
 
704
	mov	dword[esp+4+4], edx
705
	mov	dword[esp+4+4+4], eax
706
 
707
	pop	eax esi
708
;; todo: check socket options if we should add header, or just compute checksum
709
 
710
	push	edi ecx
711
	rep	movsb
712
	pop	ecx edi
713
 
714
;        [edi + IPv4_Packet.VersionAndIHL]              ; IPv4, normal length (no Optional header)
715
;        [edi + IPv4_Packet.TypeOfService]              ; nothing special, just plain ip packet
716
;        [edi + IPv4_Packet.TotalLength]
717
;        [edi + IPv4_Packet.TotalLength]                ; internet byte order
718
;        [edi + IPv4_Packet.FlagsAndFragmentOffset]
719
 
720
	mov	[edi + IPv4_Packet.HeaderChecksum], 0
721
 
722
;        [edi + IPv4_Packet.TimeToLive]                 ; ttl shl 8 + protocol
723
;        [edi + IPv4_Packet.Protocol]
724
;        [edi + IPv4_Packet.Identification]             ; fragment id
725
;        [edi + IPv4_Packet.SourceAddress]
726
;        [edi + IPv4_Packet.DestinationAddress]
727
 
728
	IPv4_checksum edi			;;;; todo: checksum for IP packet with options!
729
	add	edi, IPv4_Packet.DataOrOptional
730
	DEBUGF	1,"IPv4 Packet for device %x created successfully\n", ebx
731
	call	[ebx + NET_DEVICE.transmit]
732
	ret
733
 
734
  .error:
735
	add	esp, 6
736
  .arp_error:
737
	add	esp, 8+4+4
738
  .too_large:
739
	DEBUGF	1,"IPv4_output_raw: Failed\n"
740
	sub	edi, edi
741
	ret
742
 
743
 
1529 hidnplayr 744
;--------------------------------------------------------
745
;
746
;
747
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
748
;     dword [esp+4] = buffer size
749
;     esi = pointer to ip header in that buffer
750
;     ecx = max size of fragments
751
;
752
; OUT: /
753
;
754
;--------------------------------------------------------
1159 hidnplayr 755
 
1482 hidnplayr 756
align 4
1529 hidnplayr 757
IPv4_fragment:
1206 hidnplayr 758
 
1529 hidnplayr 759
	DEBUGF 1,"IPv4_fragment\n"
1482 hidnplayr 760
 
1529 hidnplayr 761
	and	ecx, not 111b	; align 4
1482 hidnplayr 762
 
1529 hidnplayr 763
	cmp	ecx, IPv4_Packet.DataOrOptional + 8	; must be able to put at least 8 bytes
764
	jl	.err2
1482 hidnplayr 765
 
1529 hidnplayr 766
	push	esi ecx
767
	mov	eax, [esi + IPv4_Packet.DestinationAddress]
768
	call	ARP_IP_to_MAC
769
	pop	ecx esi
770
	cmp	eax, -1
771
	jz	.err2
1482 hidnplayr 772
 
1529 hidnplayr 773
	push	ebx
774
	push	ax
1482 hidnplayr 775
 
1529 hidnplayr 776
	mov	ebx, [NET_DRV_LIST]
777
	lea	eax, [ebx + ETH_DEVICE.mac]
778
	push	eax
1482 hidnplayr 779
 
780
 
1529 hidnplayr 781
	push	esi		; ptr to ip header
782
	sub	ecx, 20 	; substract header size
783
	push	ecx		; max data size
784
	push	dword 0 	; offset
1482 hidnplayr 785
 
1529 hidnplayr 786
  .new_fragment:
787
	DEBUGF 1,"Ipv4_fragment - new_fragmentn"
1482 hidnplayr 788
 
789
 
1529 hidnplayr 790
	mov	eax, [esp + 3*4]
791
	lea	ebx, [esp + 4*4]
792
	mov	di , ETHER_IPv4
793
	call	ETH_output
1482 hidnplayr 794
 
1529 hidnplayr 795
	cmp	edi, -1
796
	jz	.err
1482 hidnplayr 797
 
1529 hidnplayr 798
; copy header
799
	mov	esi, [esp + 2*4]
800
	mov	ecx, 5	; 5 dwords: TODO: use IHL field of the header!
801
	rep	movsd
1482 hidnplayr 802
 
1529 hidnplayr 803
; copy data
804
	mov	esi, [esp + 2*4]
805
	add	esi, 20
806
	add	esi, [esp]	; offset
1482 hidnplayr 807
 
1529 hidnplayr 808
	mov	ecx, [esp + 1*4]
809
	DEBUGF 1,"IPv4_fragment - copying data (%u bytes)\n", ecx
810
	rep	movsb
1482 hidnplayr 811
 
1529 hidnplayr 812
; now, correct header
813
	mov	ecx, [esp + 1*4]
814
	add	ecx, 20
815
	xchg	cl, ch
816
	mov	[edi + IPv4_Packet.TotalLength], cx
1482 hidnplayr 817
 
1529 hidnplayr 818
	mov	ecx, [esp]		; offset
819
	xchg	cl, ch
1482 hidnplayr 820
 
1529 hidnplayr 821
;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
822
;        je      .last_fragment
823
	or	cx, 1 shl 2		; more fragments
824
;  .last_fragment:
825
	mov	[edi + IPv4_Packet.FlagsAndFragmentOffset], cx
1482 hidnplayr 826
 
1529 hidnplayr 827
	mov	[edi + IPv4_Packet.HeaderChecksum], 0
1482 hidnplayr 828
 
1529 hidnplayr 829
	;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
830
	mov	ecx, [esp + 1*4]
1482 hidnplayr 831
 
1529 hidnplayr 832
	push	edx eax
833
	IPv4_checksum edi
834
 
835
	call	[ebx + NET_DEVICE.transmit]
836
	;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
837
 
838
	mov	ecx,  [esp+4]
839
	add	[esp], ecx
840
 
841
	mov	ecx, [esp+3*4+6+4]	; ptr to begin of buff
842
	add	ecx, [esp+3*4+6+4+4]	; buff size
843
	sub	ecx, [esp+2*4]		; ptr to ip header
844
	add	ecx, [esp]		; offset
845
 
846
	DEBUGF 1,"Ipv4_fragment - bytes remaining: %u\n", ecx
847
 
848
	cmp	ecx, [esp+1*4]
849
	jge	.new_fragment
850
 
851
	mov	[esp+4], ecx		; set fragment size to remaining packet size
852
	jmp	.new_fragment
853
 
854
      .err:
855
	DEBUGF 1,"Ipv4_fragment - failed\n"
856
      .done:
857
	add	esp, 12 + 4 + 6
858
      .err2:
859
	DEBUGF 1,"Ipv4_fragment - dumping\n"
860
	call	kernel_free
861
	add	esp, 4
862
 
863
	ret
864
 
865
 
866
 
1159 hidnplayr 867
;---------------------------------------------------------------------------
868
;
869
; IPv4_dest_to_dev
870
;
1529 hidnplayr 871
; IN:  eax = Destination IP
872
; OUT: edi = device id * 4
1159 hidnplayr 873
;
874
;---------------------------------------------------------------------------
875
align 4
876
IPv4_dest_to_dev:
877
 
1529 hidnplayr 878
	cmp	eax, 0xffffffff
879
	je	.invalid
1159 hidnplayr 880
 
881
	xor	edi, edi
882
	mov	ecx, MAX_IP
883
 
884
  .loop:
1529 hidnplayr 885
	mov	ebx, [IP_LIST+edi]
886
	and	ebx, [SUBNET_LIST+edi]
887
	jz	.next
888
 
1159 hidnplayr 889
	mov	edx, eax
890
	and	edx, [SUBNET_LIST+edi]
891
 
892
	cmp	ebx, edx
893
	je	.found_it
1529 hidnplayr 894
  .next:
1159 hidnplayr 895
	add	edi, 4
896
	loop	.loop
897
 
1529 hidnplayr 898
  .invalid:
899
	xor	edi, edi			; if none found, use device 0 as default device
1159 hidnplayr 900
 
901
  .found_it:
1529 hidnplayr 902
	DEBUGF	1,"IPv4_dest_to_dev: %u\n", edi
1159 hidnplayr 903
 
904
	ret
905
 
906
 
907
 
908
;---------------------------------------------------------------------------
909
;
910
; IPv4_get_frgmnt_num
911
;
912
; IN: /
913
; OUT: fragment number in ax
914
;
915
;---------------------------------------------------------------------------
916
align 4
917
IPv4_get_frgmnt_num:
918
	xor	ax, ax	;;; TODO: replace this with real code
919
 
920
	ret
921
 
922
 
923
;---------------------------------------------------------------------------
924
;
925
; IPv4_API
926
;
927
; This function is called by system function 75
928
;
929
; IN:  subfunction number in bl
930
;      device number in bh
931
;      ecx, edx, .. depends on subfunction
932
;
933
; OUT:
934
;
935
;---------------------------------------------------------------------------
936
align 4
937
IPv4_API:
938
 
939
	movzx	eax, bh
940
	shl	eax, 2
941
 
942
	test	bl, bl
943
	jz	.packets_tx	; 0
944
	dec	bl
945
	jz	.packets_rx	; 1
946
	dec	bl
947
	jz	.read_ip	; 2
948
	dec	bl
949
	jz	.write_ip	; 3
950
	dec	bl
951
	jz	.read_dns	; 4
952
	dec	bl
953
	jz	.write_dns	; 5
954
	dec	bl
955
	jz	.read_subnet	; 6
956
	dec	bl
957
	jz	.write_subnet	; 7
958
	dec	bl
959
	jz	.read_gateway	; 8
960
	dec	bl
961
	jz	.write_gateway	; 9
962
 
1473 hidnplayr 963
  .error:
1159 hidnplayr 964
	mov	eax, -1
965
	ret
966
 
1473 hidnplayr 967
  .packets_tx:
1159 hidnplayr 968
	add	eax, IP_PACKETS_TX
969
	mov	eax, [eax]
970
	ret
971
 
1473 hidnplayr 972
  .packets_rx:
1159 hidnplayr 973
	add	eax, IP_PACKETS_RX
974
	mov	eax, [eax]
975
	ret
976
 
1473 hidnplayr 977
  .read_ip:
1159 hidnplayr 978
	add	eax, IP_LIST
979
	mov	eax, [eax]
980
	ret
981
 
1473 hidnplayr 982
  .write_ip:
1159 hidnplayr 983
	add	eax, IP_LIST
984
	mov	[eax], ecx
985
	xor	eax, eax
986
	ret
987
 
1473 hidnplayr 988
  .read_dns:
1159 hidnplayr 989
	add	eax, DNS_LIST
990
	mov	eax, [eax]
991
	ret
992
 
1473 hidnplayr 993
  .write_dns:
1159 hidnplayr 994
	add	eax, DNS_LIST
995
	mov	[eax], ecx
996
	xor	eax, eax
997
	ret
998
 
1473 hidnplayr 999
  .read_subnet:
1159 hidnplayr 1000
	add	eax, SUBNET_LIST
1001
	mov	eax, [eax]
1002
	ret
1003
 
1473 hidnplayr 1004
  .write_subnet:
1159 hidnplayr 1005
	add	eax, SUBNET_LIST
1006
	mov	[eax], ecx
1007
	xor	eax, eax
1008
	ret
1009
 
1473 hidnplayr 1010
  .read_gateway:
1159 hidnplayr 1011
	add	eax, GATEWAY_LIST
1012
	mov	eax, [eax]
1013
	ret
1014
 
1473 hidnplayr 1015
  .write_gateway:
1159 hidnplayr 1016
	add	eax, GATEWAY_LIST
1017
	mov	[eax], ecx
1018
	xor	eax, eax
1529 hidnplayr 1019
	ret