Subversion Repositories Kolibri OS

Rev

Rev 1530 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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