|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // frag.h - IPv6/IPv4 fragment queue |
|
15 // |
|
16 |
|
17 |
|
18 |
|
19 /** |
|
20 @internalComponent |
|
21 */ |
|
22 #ifndef __FRAG_H__ |
|
23 #define __FRAG_H__ |
|
24 |
|
25 #include <es_mbuf.h> |
|
26 #include "in_fmly.h" // for Panic codes |
|
27 |
|
28 class RMBufFrag : public RMBufChain |
|
29 { |
|
30 public: |
|
31 // |
|
32 // The following methods must be defined in the user implementation: |
|
33 // |
|
34 |
|
35 // Return offset of this fragment. |
|
36 TUint32 Offset() { Panic(EInet6Panic_NotSupported); return 0; } |
|
37 |
|
38 // Return the amount of data in this fragment |
|
39 TUint32 FragmentLength() { Panic(EInet6Panic_NotSupported); return 0; } |
|
40 |
|
41 // Join another fragment to this one. The fragment given in |
|
42 // parameter either directly follows this one, or overlaps |
|
43 // the tail end of this fragment. |
|
44 void Join(RMBufChain& /*aChain*/) { Panic(EInet6Panic_NotSupported); } |
|
45 }; |
|
46 |
|
47 // |
|
48 // Fragment queue template. The queue holds a number of fragments |
|
49 // of type T sorted by offset. T must be be derived from RMBufFrag. |
|
50 // Each fragment is assumed to contain enough header information |
|
51 // in order to determine the offset and data length of the fragment. |
|
52 // Whenever a new fragment is inserted in the queue that overlaps |
|
53 // or is adjacent to an existing fragment, the T::Join() method is |
|
54 // called in order to combine the two fragments into a single fragment. |
|
55 // |
|
56 // |
|
57 // In general, defragmentation is complete when the folllowing |
|
58 // two conditions are met: |
|
59 // |
|
60 // 1) RMBufFragQ::Count() == 1 |
|
61 // 2) RMBufFragQ::First() is verifiably a complete packet |
|
62 // |
|
63 template<class T> |
|
64 class RMBufFragQ : public RMBufPktQ |
|
65 { |
|
66 public: |
|
67 inline RMBufFragQ() : iCount(0) {} |
|
68 inline void Init(); |
|
69 inline void Free(); |
|
70 inline void Assign(RMBufFragQ &aQueue); |
|
71 inline TBool Remove(T &aChain); |
|
72 inline void Append(T &aChain); |
|
73 inline void Append(RMBufFragQ &aQueue); |
|
74 inline void Prepend(T& aFrag); |
|
75 inline T& First() { return (T&)RMBufPktQ::First(); } |
|
76 inline T& Last() { return (T&)RMBufPktQ::Last(); } |
|
77 inline TUint Count() { return iCount; } |
|
78 void Add(T& aFrag, TUint32* aOff = 0, TUint32* aLen = 0); |
|
79 |
|
80 protected: |
|
81 // Compare two fragment offsets. Works for all offsets < 2^31 |
|
82 // as well as for offsets requiring mod32 arithmetic, such as TCP |
|
83 // sequence numbers. |
|
84 inline TInt32 Compare(TUint32 aOffset1, TUint32 aOffset2) { return (TInt32)(aOffset1 - aOffset2); } |
|
85 |
|
86 private: |
|
87 // Just for us |
|
88 inline void Insert(RMBufChain& aNew, RMBufChain& aPrev); |
|
89 inline void Remove(RMBufChain& aNew, RMBufChain& aPrev); |
|
90 |
|
91 // Forbidden methods |
|
92 void Assign(RMBufPktQ &aQueue); |
|
93 TBool Remove(RMBufChain &aChain); |
|
94 void Append(RMBufChain &aChain); |
|
95 void Append(RMBufPktQ &aQueue); |
|
96 void Prepend(RMBufChain& aChain); |
|
97 |
|
98 // Members |
|
99 TUint iCount; |
|
100 }; |
|
101 |
|
102 template<class T> |
|
103 inline void RMBufFragQ<T>::Init() |
|
104 { |
|
105 RMBufPktQ::Init(); |
|
106 iCount = 0; |
|
107 } |
|
108 |
|
109 template<class T> |
|
110 inline void RMBufFragQ<T>::Free() |
|
111 { |
|
112 RMBufPktQ::Free(); |
|
113 iCount = 0; |
|
114 } |
|
115 |
|
116 template<class T> |
|
117 inline void RMBufFragQ<T>::Assign(RMBufFragQ &aQueue) |
|
118 { |
|
119 RMBufPktQ::Assign(aQueue); |
|
120 iCount = aQueue.iCount; |
|
121 } |
|
122 |
|
123 template<class T> |
|
124 inline TBool RMBufFragQ<T>::Remove(T &aFrag) |
|
125 { |
|
126 if (RMBufPktQ::Remove(aFrag)) |
|
127 { |
|
128 iCount--; |
|
129 return ETrue; |
|
130 } |
|
131 return EFalse; |
|
132 } |
|
133 |
|
134 template<class T> |
|
135 inline void RMBufFragQ<T>::Append(T &aFrag) |
|
136 { |
|
137 RMBufPktQ::Append(aFrag); |
|
138 iCount++; |
|
139 } |
|
140 |
|
141 template<class T> |
|
142 inline void RMBufFragQ<T>::Append(RMBufFragQ &aQueue) |
|
143 { |
|
144 RMBufPktQ::Append(aQueue); |
|
145 iCount += aQueue.iCount; |
|
146 } |
|
147 |
|
148 template<class T> |
|
149 inline void RMBufFragQ<T>::Prepend(T& aFrag) |
|
150 { |
|
151 RMBufPktQ::Prepend(aFrag); |
|
152 iCount++; |
|
153 } |
|
154 |
|
155 template<class T> |
|
156 inline void RMBufFragQ<T>::Insert(RMBufChain& aNew, RMBufChain& aPrev) |
|
157 { |
|
158 if (aPrev.IsEmpty()) |
|
159 { |
|
160 RMBufPktQ::Prepend(aNew); |
|
161 } |
|
162 else if (aPrev.Next().IsEmpty()) |
|
163 { |
|
164 RMBufPktQ::Append(aNew); |
|
165 } |
|
166 else |
|
167 { |
|
168 RMBufChain tmp; |
|
169 tmp.Assign(aNew); |
|
170 tmp.Link(aPrev.Next()); |
|
171 aPrev.Link(tmp); |
|
172 } |
|
173 iCount++; |
|
174 } |
|
175 |
|
176 // |
|
177 // This form of remove is broken in class RMBufPktQ (observed in ER3). |
|
178 // The only user is TMBufPktQIter::Remove() and the bug only appears |
|
179 // when trying to remove the last element of the queue using the |
|
180 // iterator. In this case, the iLast pointer is not updated, which |
|
181 // puts the queue into a corrupted state. Any subsequent Append() calls |
|
182 // will cause bad things to happen. |
|
183 // |
|
184 template<class T> |
|
185 inline void RMBufFragQ<T>::Remove(RMBufChain& aNew, RMBufChain& aPrev) |
|
186 { |
|
187 if (aPrev.IsEmpty()) |
|
188 { |
|
189 RMBufPktQ::Remove(aNew); |
|
190 } |
|
191 else |
|
192 { |
|
193 aNew.Assign(aPrev.Next()); |
|
194 aPrev.Link(aNew.Next()); |
|
195 aNew.Unlink(); |
|
196 if (aPrev.Next().IsEmpty()) |
|
197 iLast = aPrev; |
|
198 } |
|
199 iCount--; |
|
200 } |
|
201 |
|
202 // |
|
203 // Add a fragment to queue. The routine will try to combine fragments |
|
204 // where possible. |
|
205 // |
|
206 template<class T> |
|
207 void RMBufFragQ<T>::Add(T& aFrag, TUint32 *aOff, TUint32 *aLen) |
|
208 { |
|
209 __ASSERT_DEBUG(!aFrag.IsEmpty(), User::Panic(_L("RMBufFragQ::Add(): Zero length fragment.\r\n"),0)); |
|
210 |
|
211 TUint32 off = aFrag.Offset(); |
|
212 TUint32 len = aFrag.FragmentLength(); |
|
213 TUint32 curOff, curLen; |
|
214 |
|
215 // We can't use TMBufPktQIter because of its buggy Remove() implementation. |
|
216 RMBufChain prev, current; |
|
217 T tmpFrag; |
|
218 |
|
219 current = First(); |
|
220 while (!current.IsEmpty()) |
|
221 { |
|
222 T& cur = (T&)current; |
|
223 curOff = cur.Offset(); |
|
224 curLen = cur.FragmentLength(); |
|
225 |
|
226 // Find correct position. |
|
227 if (Compare(off, curOff + curLen) > 0) |
|
228 { |
|
229 prev = current; |
|
230 current = prev.Next(); |
|
231 continue; |
|
232 } |
|
233 |
|
234 // No overlap? Insert here. |
|
235 if (Compare(off + len, curOff) < 0) |
|
236 { |
|
237 Insert(aFrag, prev); |
|
238 break; |
|
239 } |
|
240 |
|
241 // New fragment fully overlaps queued fragment? Discard it. |
|
242 if (Compare(off, curOff) >= 0 && Compare(off + len, curOff + curLen) <= 0) |
|
243 { |
|
244 aFrag.Free(); |
|
245 off = curOff; |
|
246 len = curLen; |
|
247 break; |
|
248 } |
|
249 |
|
250 // We have found an overlapping queued fragment. Dequeue it into tmpFrag. |
|
251 if (prev.IsEmpty()) |
|
252 { |
|
253 Remove(tmpFrag); |
|
254 current = First(); |
|
255 } |
|
256 else |
|
257 { |
|
258 Remove(tmpFrag, prev); |
|
259 current = prev.Next(); |
|
260 } |
|
261 |
|
262 // Queued fragment fully overlaps new fragment? Discard it. |
|
263 if (Compare(off, curOff) <= 0 && Compare(off + len, curOff + curLen) >= 0) |
|
264 { |
|
265 tmpFrag.Free(); |
|
266 continue; |
|
267 } |
|
268 |
|
269 // Partial overlap. Determine correct order and call Join(), |
|
270 if (Compare(off, curOff) <= 0) |
|
271 { |
|
272 aFrag.Join(tmpFrag); |
|
273 tmpFrag.Free(); |
|
274 } |
|
275 else |
|
276 { |
|
277 tmpFrag.Join(aFrag); |
|
278 aFrag.Free(); |
|
279 aFrag.Assign(tmpFrag); |
|
280 off = curOff; |
|
281 } |
|
282 len = aFrag.FragmentLength(); |
|
283 } |
|
284 |
|
285 |
|
286 // Still have a fragment? It goes last then. |
|
287 if (!aFrag.IsEmpty()) |
|
288 Append(aFrag); |
|
289 |
|
290 // Return the offset and length of the contiguous block, |
|
291 // which the inserted fragment belongs to. |
|
292 if (aOff) *aOff = off; |
|
293 if (aLen) *aLen = len; |
|
294 } |
|
295 |
|
296 #endif |