|
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 // Implements the DHCPIP6 Identity Association classes |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file DHCPIP6IA.cpp |
|
20 @internalTechnology |
|
21 */ |
|
22 |
|
23 #include "DHCPIP6IA.h" |
|
24 #include "DHCP_Std.h" |
|
25 #include "DHCPServer.h" |
|
26 #include <comms-infras/metatypearray.h> |
|
27 |
|
28 #ifdef _DEBUG |
|
29 #include <e32property.h> |
|
30 #endif |
|
31 |
|
32 using namespace DHCPv6; |
|
33 |
|
34 COptionNode* CDHCPOptionIA_TA::NewL() |
|
35 { |
|
36 return new(ELeave)CDHCPOptionIA_TA(); |
|
37 } |
|
38 |
|
39 COptionNode* CDHCPOptionIA_NA::NewL() |
|
40 { |
|
41 return new(ELeave)CDHCPOptionIA_NA(); |
|
42 } |
|
43 |
|
44 CDHCPOptionIAAddress::~CDHCPOptionIAAddress() |
|
45 { |
|
46 iNext = NULL; //prevent the base from deleting its members |
|
47 } |
|
48 |
|
49 TInt CDHCPOptionIAAddress::GetAddressOptionL( TPtr8& aPtr, SIPAddressInfo& aAddressInfo ) |
|
50 { |
|
51 if ( aPtr.Length() <= KOptionHeaderLength || |
|
52 TBigEndian::GetValue( aPtr.Ptr() + KOptionCodeOffset, KOptionCodeLen ) != EIaAddr ) |
|
53 { |
|
54 return KErrNotFound; |
|
55 } |
|
56 ParseL( aPtr ); |
|
57 aPtr.Set( GetBodyDes() ); |
|
58 iRecord.ParseL( aPtr ); |
|
59 |
|
60 // Must ensure IP6 address is word aligned! So declare it locally |
|
61 TIp6Addr ip6addr; |
|
62 Mem::Copy(&ip6addr,iAddress.GetBodyPtr(),KIp6AddressLength); |
|
63 |
|
64 aAddressInfo.iAddress.SetAddress( ip6addr ); |
|
65 aAddressInfo.iPreferredLifeTime = iPreferredLifeTime.GetBigEndian(); |
|
66 aAddressInfo.iValidLifeTime = iValidLifeTime.GetBigEndian(); |
|
67 CDHCPOptionStatusCode* pStatus = static_cast<CDHCPOptionStatusCode*>(GetOptions().FindOption( EStatusCode )); |
|
68 aAddressInfo.iStatusCode = pStatus ? pStatus->GetStatusCode() : ESuccess; |
|
69 |
|
70 return KErrNone; |
|
71 } |
|
72 |
|
73 |
|
74 TInt CDHCPOptionIAAddress::AddAddressOptionL( TPtr8& aPtr, SIPAddressInfo& aAddressInfo, TStatusCodes aStatusCodeToSend ) |
|
75 { |
|
76 InitialiseL(aPtr); |
|
77 CDHCPOptionStatusCode* option = NULL; |
|
78 if(aStatusCodeToSend != EStatusUnknown) |
|
79 { |
|
80 option = static_cast<CDHCPOptionStatusCode*>(iOptions.AddNodeL(EStatusCode, KDHCPOptionStatusCodeLength)); |
|
81 } |
|
82 iRecord.InitialiseL(aPtr); |
|
83 Header().SetInitialValue(KDHCPOptionIAAddressWithStatusCodeLength - KOptionHeaderLength); |
|
84 SetLength(); |
|
85 |
|
86 SetOpCode(static_cast<TUint>(EIaAddr)); |
|
87 TIp6Addr* ip6addr = reinterpret_cast<TIp6Addr*>(iAddress.GetBodyPtr() ); |
|
88 |
|
89 //-- carefully copy one object to another. See function description |
|
90 ObjectByteCopy(ip6addr, &aAddressInfo.iAddress.Ip6Address()); |
|
91 |
|
92 iPreferredLifeTime.SetBigEndian( aAddressInfo.iPreferredLifeTime ); |
|
93 iValidLifeTime.SetBigEndian( aAddressInfo.iValidLifeTime ); |
|
94 if(option) |
|
95 { |
|
96 option->SetOpCode(static_cast<TUint>(EStatusCode)); |
|
97 option->SetStatusCode(aStatusCodeToSend); |
|
98 } |
|
99 |
|
100 return KErrNone; |
|
101 } |
|
102 |
|
103 TPtr8 CDHCPOptionIA_TA::GetOptionsDes() const |
|
104 { |
|
105 TPtr8 ptr(GetBodyDes()); |
|
106 TInt len = ptr.Length() - KDHCPOptionIA_NATInitLength; |
|
107 return TPtr8( const_cast<TUint8*>(ptr.Ptr()) + KDHCPOptionIA_IAIDLength, len, len ); |
|
108 } |
|
109 |
|
110 TPtr8 CDHCPOptionIA_NA::GetOptionsDes() const |
|
111 { |
|
112 TPtr8 ptr(GetBodyDes()); |
|
113 TInt len = ptr.Length() - KDHCPOptionIA_NATInitLength; |
|
114 return TPtr8( const_cast<TUint8*>(ptr.Ptr()) + KDHCPOptionIA_NATInitLength, len, len ); |
|
115 } |
|
116 |
|
117 START_ATTRIBUTE_TABLE( SIdentityAssociationConfigInfo, KDHCPv6Persinstence, 0 ) |
|
118 REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfo, iIAID, TMetaNumber ) |
|
119 REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfo, iAddressInfo, TMetaArray<SIPAddressInfo> ) |
|
120 END_ATTRIBUTE_TABLE() |
|
121 |
|
122 void SIdentityAssociationConfigInfo::Reset() |
|
123 { |
|
124 TDhcpRnd rnd; |
|
125 iIAID = rnd.Rnd( KDHCPv6IA_NANumberSpaceMin, KDHCPv6IA_NANumberSpaceMax ); |
|
126 iAddressInfo.Reset(); |
|
127 } |
|
128 |
|
129 void SIdentityAssociationConfigInfo::SetAddressStatus( TInt aIndex, TStatusCodes aStatusCode ) |
|
130 { |
|
131 if ( aIndex == KAddrIndexAll ) |
|
132 { |
|
133 TInt count = iAddressInfo.Count(); |
|
134 for(TInt addrInfoIdx=0;addrInfoIdx<count;addrInfoIdx++) |
|
135 { |
|
136 iAddressInfo[addrInfoIdx].iStatusCode = aStatusCode; |
|
137 } |
|
138 } |
|
139 else |
|
140 { |
|
141 iAddressInfo[aIndex].iStatusCode = aStatusCode; |
|
142 } |
|
143 } |
|
144 |
|
145 TInt SIdentityAssociationConfigInfo::AddressInfo( TInt aIndex, TStatusCodes aStatusCode ) const |
|
146 { |
|
147 TInt count = iAddressInfo.Count(); |
|
148 for(TInt addrInfoIdx=aIndex;addrInfoIdx<count;addrInfoIdx++) |
|
149 { |
|
150 if ( (iAddressInfo[addrInfoIdx].iStatusCode & EStatusUnknown) == aStatusCode ) |
|
151 { |
|
152 return addrInfoIdx + 1; |
|
153 } |
|
154 } |
|
155 return KErrNotFound; |
|
156 } |
|
157 |
|
158 TInt SIdentityAssociationConfigInfo::AddAddressesL( CDHCPOptionIA& aDHCPOptionIA, TMessageType aMessageType ) |
|
159 { |
|
160 TInt addrInfoIdx = 0; |
|
161 TStatusCodes statusCode = EStatusUnknown; |
|
162 TStatusCodes statusCodeToSend = EStatusUnknown; |
|
163 TInt remove = 0; |
|
164 |
|
165 switch(aMessageType) |
|
166 { |
|
167 case ESolicit: |
|
168 break; |
|
169 case ERequest: |
|
170 statusCode = EMarkToRequest; |
|
171 break; |
|
172 case EConfirm: |
|
173 case ERenew: |
|
174 case ERebind: |
|
175 statusCode = ESuccess; |
|
176 statusCodeToSend = ESuccess; |
|
177 break; |
|
178 case ERelease: |
|
179 statusCode = EMarkForRelease; |
|
180 statusCodeToSend = ESuccess; |
|
181 remove = 1; |
|
182 break; |
|
183 case EDecline: |
|
184 statusCode = EMarkForDecline; |
|
185 statusCodeToSend = ENoBinding; |
|
186 remove = 1; |
|
187 break; |
|
188 default: |
|
189 break; |
|
190 } |
|
191 //make a room for address options |
|
192 TInt len = aDHCPOptionIA.GetLength(); |
|
193 TInt newlen = len + (KDHCPOptionIAAddressWithStatusCodeLength * iAddressInfo.Count()); |
|
194 //see DhcpIP6Msg.h comment !!!!BEWARE as to how the msg buffer allocation is handled |
|
195 //so far |
|
196 CDHCPOptionIAAddress* optionIaAddress = CDHCPOptionIAAddress::NewL(); |
|
197 CleanupStack::PushL( optionIaAddress ); |
|
198 TPtr8 ptr( aDHCPOptionIA.GetBodyPtr(), len, newlen ); |
|
199 ptr.SetLength( len ); |
|
200 |
|
201 while ( (addrInfoIdx = AddressInfo( addrInfoIdx, statusCode )) != KErrNotFound ) |
|
202 { |
|
203 SIPAddressInfo& addressInfo = iAddressInfo[addrInfoIdx - 1]; |
|
204 optionIaAddress->AddAddressOptionL( ptr, addressInfo, statusCodeToSend ); |
|
205 if ( remove ) |
|
206 { |
|
207 iAddressInfo.Remove( --addrInfoIdx ); |
|
208 } |
|
209 } |
|
210 //write the IA option len into the msg buffer |
|
211 aDHCPOptionIA.Header().SetInitialValue( ptr.Length() ); |
|
212 aDHCPOptionIA.SetLength(); |
|
213 CleanupStack::PopAndDestroy(); |
|
214 return ptr.Length() - len; //return te length of what we've just put in (address options) |
|
215 } |
|
216 |
|
217 void SIdentityAssociationConfigInfo::ExtractAddressesL( CDHCPOptionIA& aDHCPOptionIA, TUint32 aRebindTimeSpan ) |
|
218 { |
|
219 CDHCPOptionIAAddress* optionIaAddress = CDHCPOptionIAAddress::NewL(); |
|
220 CleanupStack::PushL( optionIaAddress ); |
|
221 |
|
222 TPtr8 ptr( aDHCPOptionIA.GetOptionsDes() ); |
|
223 SIPAddressInfo addressInfoNew; |
|
224 |
|
225 while (optionIaAddress->GetAddressOptionL( ptr, addressInfoNew ) == KErrNone) |
|
226 { |
|
227 iAddressInfo.AppendL( addressInfoNew ); |
|
228 } |
|
229 CleanupStack::PopAndDestroy(); |
|
230 |
|
231 //check validity and remove what's not needed |
|
232 for(TInt addrInfoIdx=0;addrInfoIdx<iAddressInfo.Count();addrInfoIdx++) |
|
233 { |
|
234 SIPAddressInfo& addressInfo = iAddressInfo[addrInfoIdx]; |
|
235 /*the RFC3315 doesn't explicitly say this but since it says: |
|
236 [At time T2(our aRebindTimeSpan) for an IA the client initiates a Rebind/Reply message exchange |
|
237 with any available server. The message exchange is terminated when the valid lifetimes of all |
|
238 the addresses assigned to the IA expire] |
|
239 the following check seems like a good idea*/ |
|
240 if ( addressInfo.iPreferredLifeTime > addressInfo.iValidLifeTime || |
|
241 aRebindTimeSpan > addressInfo.iValidLifeTime || |
|
242 addressInfo.iStatusCode != ESuccess ) |
|
243 { |
|
244 addressInfo.iStatusCode = EMarkForDecline; |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 START_ATTRIBUTE_TABLE( SIdentityAssociationConfigInfoNA, KDHCPv6Persinstence, 0 ) |
|
250 REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfoNA, iT1, TMetaNumber ) |
|
251 REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfoNA, iT2, TMetaNumber ) |
|
252 END_ATTRIBUTE_TABLE_BASE(SIdentityAssociationConfigInfo,KDHCPv6PersinstenceId.iUid) |
|
253 |
|
254 void SIdentityAssociationConfigInfoNA::ExtractIAOptionInfoL( CDHCPOptionIA_NA& aDHCPOptionIA ) |
|
255 { |
|
256 iT1 = aDHCPOptionIA.GetT1(); |
|
257 iT2 = aDHCPOptionIA.GetT2(); |
|
258 ExtractAddressesL( aDHCPOptionIA, iT2 ); |
|
259 } |
|
260 |
|
261 void TInterfaceConfigInfo::AppendIAOptionsL(CDHCPMessageHeaderIP6& aMessage, TMessageType aMessageType) |
|
262 { |
|
263 CDHCPOptionIA_NA* pIA_NA = static_cast<CDHCPOptionIA_NA*>(aMessage.AddOptionL(EIaNa, KDHCPOptionIA_NATInitLength)); |
|
264 pIA_NA->SetIAID(iSIdentityAssociationConfigInfoNA.IaId()); |
|
265 // indicate no preference for T1 and T2 |
|
266 pIA_NA->SetT1(KIA_NoTimePreference); |
|
267 pIA_NA->SetT2(KIA_NoTimePreference); |
|
268 switch(aMessageType) |
|
269 { |
|
270 case ESolicit: |
|
271 break; |
|
272 case EConfirm: |
|
273 case ERenew: |
|
274 case ERebind: |
|
275 pIA_NA->SetT1(iSIdentityAssociationConfigInfoNA.iT1); |
|
276 pIA_NA->SetT2(iSIdentityAssociationConfigInfoNA.iT2); |
|
277 //fall through |
|
278 case ERequest: |
|
279 case ERelease: |
|
280 case EDecline: |
|
281 { |
|
282 TInt addrOptLen = iSIdentityAssociationConfigInfoNA.AddAddressesL(*pIA_NA,aMessageType); |
|
283 TPtr8 msg = aMessage.Message().Des(); |
|
284 msg.SetLength( msg.Length() + addrOptLen); |
|
285 break; |
|
286 } |
|
287 default: |
|
288 User::Leave(KErrNotSupported); |
|
289 } |
|
290 |
|
291 } |
|
292 |
|
293 void TInterfaceConfigInfo::ParseIAOptionsL(CDHCPMessageHeaderIP6& aMessage) |
|
294 { |
|
295 // Find an NA option |
|
296 CDHCPOptionIA_NA* optionIa = static_cast<CDHCPOptionIA_NA*>(aMessage.GetOptions().FindOption(EIaNa)); |
|
297 if (!optionIa || optionIa->GetT1() > optionIa->GetT2()) |
|
298 {//nothing to do the fact that we don't have any address is picked up when the address is being |
|
299 //congfigured |
|
300 return; |
|
301 } |
|
302 if ( aMessage.GetMessageType() == EReply ) |
|
303 { |
|
304 iSIdentityAssociationConfigInfoNA.ResetAddressInfos(); |
|
305 iSIdentityAssociationConfigInfoNA.ExtractIAOptionInfoL( *optionIa ); |
|
306 } |
|
307 } |
|
308 |
|
309 void TInterfaceConfigInfo::CheckForUnicast( CDHCPMessageHeaderIP6& aMessage ) |
|
310 { |
|
311 COptionNode* pNode = aMessage.GetOptions().FindOption(EUnicast); |
|
312 if ( pNode ) |
|
313 { |
|
314 iUseUnicast = ETrue; |
|
315 |
|
316 // Must ensure IP6 address is word aligned! So declare it locally |
|
317 TIp6Addr ip6addr; |
|
318 Mem::Copy(&ip6addr,pNode->GetBodyPtr(),KIp6AddressLength); |
|
319 |
|
320 iServerAddress.SetAddress( ip6addr ); |
|
321 } |
|
322 } |
|
323 |
|
324 void TInterfaceConfigInfo::GetServerAddress( TInetAddr& aAddress ) // to send/receive data |
|
325 { |
|
326 __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("TInterfaceConfigInfo::GetServerAddress unicast %d"), iUseUnicast)); |
|
327 if ( iUseUnicast ) |
|
328 { |
|
329 aAddress = iServerAddress; |
|
330 } |
|
331 else |
|
332 { |
|
333 aAddress.SetAddress( KDHCPv6RelayAgentsNServers ); |
|
334 } |
|
335 #ifdef _DEBUG |
|
336 // Simulate initialisation, renewal or rebind failure by using the wrong port. |
|
337 if( ( CDHCPServer::DebugFlags() & KDHCP_FailDiscover ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRenew ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRebind ) ) |
|
338 { |
|
339 aAddress.SetPort(KDhcpv6WrongDestPort); |
|
340 } |
|
341 else |
|
342 { |
|
343 TInt destPort; |
|
344 RProperty::Get(KMyPropertyCat, KMyPropertyDestPortv6, destPort); |
|
345 aAddress.SetPort(destPort); |
|
346 } |
|
347 #else |
|
348 aAddress.SetPort(KDhcpv6DestPort); |
|
349 #endif |
|
350 } |
|
351 |
|
352 /** |
|
353 * Creates one IAID for TA(SIdentityAssociationConfigInfoTA) and |
|
354 * one for NA(SIdentityAssociationConfigInfoNA) in case they don't exist yet |
|
355 * (restored after reboot, sleep,....) |
|
356 * |
|
357 * @see SIdentityAssociationConfigInfoTA, SIdentityAssociationConfigInfoNA |
|
358 * @internalTechnology |
|
359 */ |
|
360 void DHCPv6::TInterfaceConfigInfo::Reset() |
|
361 { |
|
362 ResetUseUnicast(); |
|
363 //iSIdentityAssociationConfigInfoTA.iIAID = rnd.Rnd( KDHCPv6IA_TANumberSpaceMin, KDHCPv6IA_TANumberSpaceMax ); |
|
364 iSIdentityAssociationConfigInfoNA.Reset(); |
|
365 |
|
366 // Clear the DHCP server address now that we no longer have a lease. |
|
367 iServerAddress.SetAddress( KInet6AddrNone ); |
|
368 } |