networkprotocols/iphook/inhook6/src/in_pkt.cpp
changeset 0 af10295192d8
child 5 1422c6cd3f0c
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2006-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 // in_pkt.cpp - packet handling routines
       
    15 // Mainly the RMBufPacketPeek implementation
       
    16 // + extension header locations
       
    17 // + method for adding a destination option
       
    18 //
       
    19 
       
    20 #include "in_pkt.h"
       
    21 #include "ext_hdr.h"
       
    22 
       
    23 #define OPTIMIZE_PADDING
       
    24 
       
    25 
       
    26 // RMBufPacketPeek
       
    27 // ***************
       
    28 
       
    29 EXPORT_C TUint8 *TInet6PacketBase::Access(RMBufChain &aPacket, TInt aOffset, TInt aSize, TInt aMin)
       
    30 	/**
       
    31 	* Accesses a contiguous block of memory within RMBufChain starting
       
    32 	* at specified offset.
       
    33 	*
       
    34 	* Attempts to map aSize amount of contiguous RMBuf space at
       
    35 	* the specified offset, by rearranging the RMBufs,
       
    36 	* if necessary.
       
    37 	*
       
    38 	* If aSize amount is not available, the returned pointer maps
       
    39 	* the maximum available space (< aSize).
       
    40 	*
       
    41 	* @param	aSize
       
    42 	*	The size of the requested contiguous mapping (in octets).
       
    43 	*	The value cannot be larger than KMBufSmallSize. If aSize <= 1,
       
    44 	*	the method will return availabe contiguous mapping at the
       
    45 	*	indicated offset without rearranging the RMBuf chain. Values
       
    46 	*	larger than 1 may require rearrangement to get the requested
       
    47 	*	area into single RMBuf.
       
    48 	* @param	aOffset
       
    49 	*	The offset to the beginning of the area. The value MUST
       
    50 	*	be in range: 0 <= aOffset <= Length().
       
    51 	* @param	aMin
       
    52 	*	The minimum accepted iLength. If iLength is less that aMin,
       
    53 	*	then returns NULL.
       
    54 	* @return
       
    55 	*	A pointer to the data starting at indicated
       
    56 	*	offset. The iLength is set to the
       
    57 	*	maximum available contiguous data starting from the
       
    58 	*	requested offset. iLength is always <= KMBufSmallSize.
       
    59 	* @note
       
    60 	*	The length can be either less or
       
    61 	*	larger than aSize. The caller must verify the returned
       
    62 	*	length to detect whether Access succeeded.
       
    63 	*/
       
    64 	{
       
    65 
       
    66 	//
       
    67 	// Can only map at most KMBufSmallSize bytes
       
    68 	// (truncate aSize to avoid Panics from the Align)
       
    69 	//
       
    70 	if (aSize > KMBufSmallSize)
       
    71 		aSize = KMBufSmallSize;
       
    72 
       
    73 	for (int already_tried = 0; ;already_tried = 1)
       
    74 		{
       
    75 		RMBuf *p;
       
    76 		TInt offset, len;
       
    77 		iLength = 0;
       
    78 
       
    79 		if (aPacket.IsEmpty() || !aPacket.Goto(aOffset, p, offset, len))
       
    80 			return NULL;
       
    81 		else if ((aSize <= len && (offset & iAlign) == 0) || already_tried)
       
    82 			{
       
    83 			if (len < aMin)
       
    84 				return NULL;
       
    85 			iLength = len;
       
    86 			return p->Buffer() + offset;
       
    87 			}
       
    88 		// The requested alignment value is not
       
    89 		// satisfied!
       
    90 		//
       
    91 		// Brute force buffer mangling here: just
       
    92 		// Split the chain at requested point, apply
       
    93 		// align to the tail part, and then join the
       
    94 		// pieces together (assuming this join operation
       
    95 		// does not undo the align...)
       
    96 		// (If this is going to occur frequently
       
    97 		// some optimizations is in order... -- msa)
       
    98 		//
       
    99 		//
       
   100 		// *NOTE*
       
   101 		//		If aOffset == 0, SplitL works weird (IMHO): it does
       
   102 		//		nothing (when it logically should move all to the
       
   103 		//		tail part!). Thus, zero offset needs to be handled
       
   104 		//		specially (sort of optimizing, so it's not too bad)
       
   105 		//		-- msa
       
   106 		//
       
   107 		if (aOffset > 0)
       
   108 			{
       
   109 			RMBufChain tail;
       
   110 			TInt err = aPacket.Split(aOffset, tail);
       
   111 			if (err == KErrNone && !tail.IsEmpty())
       
   112 				{
       
   113 				tail.Align(aSize);
       
   114 				aPacket.Append(tail);
       
   115 				}
       
   116 			}
       
   117 		else
       
   118 			aPacket.Align(aSize);
       
   119 		// And now just retry the Goto and use that
       
   120 		// result as is (either we succeeded or not)
       
   121 		}
       
   122 	}
       
   123 
       
   124 EXPORT_C TPtr8 RMBufPacketPeek::Access(TInt aSize, TUint aOffset)
       
   125 	/**
       
   126 	* Accesses a contiguous block of memory within RMBufChain starting
       
   127 	* at specified offset.
       
   128 	*
       
   129 	* Attempts to map aSize amount of contiguous RMBuf space at
       
   130 	* the specified offset into a TPtr8, by rearranging the RMBufs,
       
   131 	* if necessary.
       
   132 	*
       
   133 	* If aSize amount is not available, the returned pointer maps
       
   134 	* the maximum available space (< aSize).
       
   135 	*
       
   136 	* @param	aSize
       
   137 	*	The size of the requested contiguous mapping (in octets).
       
   138 	*	The value cannot be larger than KMBufSmallSize. If aSize <= 1,
       
   139 	*	the method will return availabe contiguous mapping at the
       
   140 	*	indicated offset without rearranging the RMBuf chain. Values
       
   141 	*	larger than 1 may require rearrangement to get the requested
       
   142 	*	area into single RMBuf.
       
   143 	* @param	aOffset
       
   144 	*	The offset to the beginning of the area. The value MUST
       
   145 	*	be in range: 0 <= aOffset <= Length().
       
   146 	* @return
       
   147 	*	A pointer descriptor for the data starting at indicated
       
   148 	*	offset. The length of the descriptor is set to the
       
   149 	*	maximum available contiguous data starting from the
       
   150 	*	requested offset. Length is always <= KMBufSmallSize.
       
   151 	* @note
       
   152 	*	The length can be either less or
       
   153 	*	larger than aSize. The caller must verify the returned
       
   154 	*	length to detect whether Access succeeded.
       
   155 	*/
       
   156 	{
       
   157 	TInet6PacketBase map(TInet6PacketBase::EAlign1);
       
   158 	TUint8 *const ptr = map.Access(*this, aOffset, aSize, 1);
       
   159 	return TPtr8(ptr, map.iLength, map.iLength);
       
   160 	}
       
   161 
       
   162 
       
   163 EXPORT_C TIpHeader *RMBufPacketPeek::GetIpHeader()
       
   164 	/**
       
   165 	* Access IP header (v4 or v6) from the packet at offset 0.
       
   166 	*
       
   167 	* @return IP header (or NULL).
       
   168 	*	A non-NULL return implies that full header, either IPv4 or
       
   169 	*	IPv6 is accessible through the pointer. This method is
       
   170 	*	intended to save code space, and not necessarily for
       
   171 	*	speed...
       
   172 	*/
       
   173 	{
       
   174 	TInet6Packet<TIpHeader> ip(*this);
       
   175 	if (ip.iHdr)
       
   176 		{
       
   177 		if (ip.iHdr->ip4.Version() == 4)
       
   178 			{
       
   179 			// Need to do sanity check on header length (because it can be garbage)
       
   180 			const TInt hlen = ip.iHdr->ip4.HeaderLength();
       
   181 			if (hlen >= TInet6HeaderIP4::MinHeaderLength() && ip.iLength >= hlen)
       
   182 				return (TIpHeader *)ip.iHdr;
       
   183 			}
       
   184 		else if (ip.iHdr->ip4.Version() == 6)
       
   185 			{
       
   186 			if (ip.iLength >= TInet6HeaderIP::MinHeaderLength())
       
   187 				return (TIpHeader *)ip.iHdr;
       
   188 			}
       
   189 		}
       
   190 	return NULL;
       
   191 	}
       
   192 
       
   193 // TPacketPocker
       
   194 // *************
       
   195 
       
   196 EXPORT_C TPacketPoker::TPacketPoker(RMBufChain &aChain) : iCurrent(aChain.First()), iOffset(0), iTail(0)
       
   197 	/**
       
   198 	* Constructor.
       
   199 	*
       
   200 	* @param aChain	The RMBuf chain to be poked.
       
   201 	*/
       
   202 	{
       
   203 	// Find initial value for iTail.
       
   204 	while (iCurrent)
       
   205 		{
       
   206 		iTail = iCurrent->Length();
       
   207 		if (iTail > 0)
       
   208 			break;
       
   209 		// Ugh. There have been RMBuf's with ZERO length!
       
   210 		iCurrent = iCurrent->Next();
       
   211 		}
       
   212 	}
       
   213 
       
   214 EXPORT_C void TPacketPoker::OverL(TInt aSize)
       
   215 	/**
       
   216 	* Skip over bytes.
       
   217 	*
       
   218 	* @param aSize	The number of bytes to skip
       
   219 	* @leave KErrEof, if skipped past end of chain.
       
   220 	*/
       
   221 	{
       
   222 	for (;;)
       
   223 		{
       
   224 		if (aSize < iTail)
       
   225 			{
       
   226 			iTail -= aSize;		// Results always: iTail > 0!
       
   227 			iOffset += aSize;
       
   228 			return;
       
   229 			}
       
   230 		aSize -= iTail;
       
   231 		if ((iCurrent = iCurrent->Next()) == NULL)
       
   232 			{
       
   233 			iTail = 0;			// All scanned, at end of chain
       
   234 			if (aSize > 0)		// --> Error, if request was more
       
   235 				User::Leave(KErrEof);	// KErrEof used (for lack of any better)
       
   236 			return;
       
   237 			}
       
   238 		iOffset = 0;
       
   239 		iTail = iCurrent->Length();
       
   240 		}
       
   241 	}
       
   242 
       
   243 EXPORT_C TUint8 *TPacketPoker::AdjustL(TInt aSize)
       
   244 	/**
       
   245 	* Arrange contiguous run of bytes.
       
   246 	*
       
   247 	* Arragen content of RMBuf chain so that starting from
       
   248 	* the current offset, a number of bytes is accessible
       
   249 	* in contiguous memory.
       
   250 	*
       
   251 	* @param aSize The requested length,
       
   252 	* @return The pointer to be beginning of area.
       
   253 	* @leave KErrEof, if request cannot be satisfied.
       
   254 	*/
       
   255 	{
       
   256 	RMBufChain chain(iCurrent);
       
   257 	if (iOffset > 0)
       
   258 		{
       
   259 		RMBufChain tail;
       
   260 		chain.SplitL(iOffset, tail);
       
   261 		tail.Align(aSize);
       
   262 		chain.Append(tail);
       
   263 		}
       
   264 	else
       
   265 		chain.Align(aSize);
       
   266 	ASSERT(iCurrent == chain.First());
       
   267 	iTail = iCurrent->Length() - iOffset;
       
   268 	if (iTail < aSize)			// Align failed?
       
   269 		User::Leave(KErrEof);	// KErrEof used (for lack of any better)
       
   270 	return Ptr();
       
   271 	}
       
   272 
       
   273 //
       
   274 
       
   275 EXPORT_C TBool TPacketPoker::IsExtensionHeader(TInt aProtocolId)
       
   276 	/**
       
   277 	* Tests whether a protocol is a known IPv6 extension header using the standard format.
       
   278 	* 
       
   279 	* @param aProtocolId	Protocol ID to test.
       
   280 	* @return ETrue,
       
   281 	* 	if the protocol header follows the generic IPv6 extension
       
   282 	*	header format (TInet6HeaderExtension).
       
   283 	*/
       
   284 	{
       
   285 	// If more of these are known, could perhaps implement a
       
   286 	// static boolean table indexed by protocol -- msa
       
   287 	return
       
   288 		(
       
   289 		aProtocolId == STATIC_CAST(TInt, KProtocolInet6HopOptions) ||
       
   290 		aProtocolId == STATIC_CAST(TInt, KProtocolInet6DestinationOptions) ||
       
   291 		aProtocolId == STATIC_CAST(TInt, KProtocolInet6RoutingHeader)
       
   292 		);
       
   293 	}
       
   294 
       
   295 // TPacketHead
       
   296 // ***********
       
   297 
       
   298 EXPORT_C TBool TPacketHead::ExtHdrGet(TInt aType, TInt& aOfs, TInt& aLen)
       
   299 	/**
       
   300 	* Gets the offset and length of an extension header.
       
   301 	*
       
   302 	* @param aType Extension header type
       
   303 	* @retval aOfs On return, the header offset
       
   304 	* @retval aLen On return, the header length
       
   305 	* @return ETrue if the header was found, otherwise EFalse 
       
   306 	*/
       
   307 	{
       
   308 	if (iPacket.IsEmpty())
       
   309 		return EFalse;
       
   310 
       
   311 	TInt type = ip6.NextHeader();
       
   312 	TInt ofs = 0;
       
   313 
       
   314 	while (TPacketPoker::IsExtensionHeader(type) && ofs<iOffset)
       
   315 		{
       
   316 		//TInet6Options is about as generic Extension Header class as possible.
       
   317 		//Thus no need to create another one.
       
   318 		TInet6Packet<TInet6Options> hdr(iPacket, ofs);
       
   319 		if (hdr.iHdr == NULL) return EFalse;
       
   320 		
       
   321 		if (type == aType)
       
   322 			{
       
   323 			aOfs = ofs;
       
   324 			aLen = hdr.iHdr->HeaderLength();
       
   325 			return ETrue;
       
   326 			}
       
   327 		type = hdr.iHdr->NextHeader();
       
   328 		ofs += hdr.iHdr->HeaderLength();
       
   329 		}
       
   330 	return EFalse;
       
   331 	}
       
   332 
       
   333 EXPORT_C TBool TPacketHead::ExtHdrGetOrPrependL(TInt aType, TInt& aOfs, TInt& aLen)
       
   334 	/**
       
   335 	* Gets the offset and length of an extension header, or if it doesn't already 
       
   336 	* exist, creates the header before all other extension headers.
       
   337 	*
       
   338 	* @param aType
       
   339 	*	Extension header type
       
   340 	* @retval aOfs
       
   341 	*	If the header is created, this specifies the header offset. If
       
   342 	*	the header already exists, on return: the actual header offset.
       
   343 	* @retval aLen
       
   344 	*	If the header is created, this specifies the header length. If
       
   345 	*	the header already exists, on return: the actual header length.
       
   346 	* @return
       
   347 	*	ETrue if the header was found, EFalse if the header was created.
       
   348 	*/
       
   349 	{
       
   350 	if (ExtHdrGet(aType, aOfs, aLen))
       
   351 		return ETrue;
       
   352 	ASSERT(aLen && ((aLen & 7) == 0));
       
   353 
       
   354 	if (iPacket.IsEmpty())
       
   355 		{
       
   356 		iPacket.AllocL(aLen);
       
   357 		}
       
   358 	else
       
   359 		{
       
   360 		iPacket.PrependL(aLen);
       
   361 		}
       
   362 	
       
   363 	//Zero out the header
       
   364 	iPacket.FillZ(aLen);
       
   365 	TInet6Packet<TInet6Options> hdr(iPacket, 0);
       
   366 	if (hdr.iHdr == NULL)
       
   367 		{
       
   368 		iPacket.TrimStart(aLen);
       
   369 		User::Leave(KErrGeneral);
       
   370 		}
       
   371 	
       
   372 	hdr.iHdr->SetNextHeader(ip6.NextHeader());
       
   373 	ip6.SetNextHeader(aType);
       
   374 	hdr.iHdr->SetHdrExtLen((aLen >> 3) - 1);
       
   375 
       
   376 	aOfs = 0;
       
   377 	iOffset += aLen;
       
   378 	return EFalse;
       
   379 	}
       
   380 
       
   381 EXPORT_C TBool TPacketHead::ExtHdrGetOrAppendL(TInt aType, TInt& aOfs, TInt& aLen)
       
   382 	/**
       
   383 	* Gets the offset and length of an extension header, or if it doesn't already 
       
   384 	* exist, creates the header after all other extension headers.
       
   385 	*
       
   386 	* @param aType	Extension header type
       
   387 	* @retval aOfs
       
   388 	*	If the header is created, this specifies the header offset. If
       
   389 	*	the header already exists, on return, the actual header offset.
       
   390 	* @retval aLen
       
   391 	*	If the header is created, this specifies the header length. If
       
   392 	*	the header already exists, on return, the actual header length.
       
   393 	* @return ETrue if the header was found, EFalse if the header was created 
       
   394 	*/
       
   395 	{
       
   396 	if (ExtHdrGet(aType, aOfs, aLen)) return ETrue;
       
   397 	if (iPacket.IsEmpty()) return ExtHdrGetOrPrependL(aType, aOfs, aLen);
       
   398 	ASSERT(aLen && ((aLen & 7) == 0));
       
   399 	
       
   400 	TInt nxt = ip6.NextHeader();
       
   401 	TInt ofs = 0;
       
   402 	FOREVER
       
   403 		{
       
   404 		TInet6Packet<TInet6Options> hdr(iPacket, ofs);
       
   405 		if (hdr.iHdr == NULL)
       
   406 			User::Leave(KErrGeneral);
       
   407 		
       
   408 		nxt = hdr.iHdr->NextHeader();
       
   409 		ofs += hdr.iHdr->HeaderLength();
       
   410 		if (ofs >= iOffset)
       
   411 			{
       
   412 			hdr.iHdr->SetNextHeader(aType);
       
   413 			break;
       
   414 			}
       
   415 		}
       
   416 	
       
   417 	RMBufChain tail;
       
   418 	tail.AllocL(aLen);
       
   419 	tail.FillZ();
       
   420 	iPacket.Append(tail);
       
   421 
       
   422 	TInet6Packet<TInet6Options> hdr(iPacket, iOffset);
       
   423 	if (hdr.iHdr == NULL)
       
   424 		{
       
   425 		iPacket.TrimEnd(iOffset);
       
   426 		User::Leave(KErrGeneral);
       
   427 		}
       
   428 	hdr.iHdr->SetNextHeader(nxt);
       
   429 	hdr.iHdr->SetHdrExtLen((aLen >> 3) - 1);
       
   430 	
       
   431 	aOfs = iOffset;
       
   432 	iOffset += aLen;
       
   433 	return EFalse;
       
   434 	}
       
   435 
       
   436 //
       
   437 // TODO: Possibility to replace existing padding with an option which
       
   438 //       would preserve the alignment. (eg. Home Address is kind of Pad2)
       
   439 //
       
   440 EXPORT_C void TPacketHead::AddDestinationOptionL(const TUint8* aOption, TUint8 aLen, TUint8 aAlign/*=0*/, TUint8 aModulo/*=4*/)
       
   441 	{
       
   442 	/**
       
   443 	* Adds a Destination Option extension header option.
       
   444 	*
       
   445 	* If no Destination Option extension header already exists, one is created
       
   446 	* as the first extension header. The option is aligned according to the
       
   447 	* specified aAlign and aModulo parameters.
       
   448 	*
       
   449 	* @param aOption
       
   450 	*	Option Data
       
   451 	* @param aLen
       
   452 	*	Option Data length
       
   453 	* @param aAlign
       
   454 	*	Option alignment requirement. The default is no alignment.
       
   455 	* @param aModulo
       
   456 	*	Option must start at an octect position which is a multiple 
       
   457 	*	of the specified value
       
   458 	*/
       
   459 	TPtrC8 ptr(aOption, aLen);
       
   460 	AddDestinationOptionL(ptr, aAlign, aModulo);
       
   461 	}
       
   462 
       
   463 EXPORT_C void TPacketHead::AddDestinationOptionL(const TPtrC8& aOption, TUint8 aAlign/*=0*/, TUint8 aModulo/*=4*/)
       
   464 	/**
       
   465 	* Adds a Destination Option extension header option.
       
   466 	*
       
   467 	* If no Destination Option extension header already exists, one is
       
   468 	* created as the first extension header. The option is aligned
       
   469 	* according to the specified aAlign and aModulo parameters.
       
   470 	*
       
   471 	* @param aOption
       
   472 	*	Pointer to the start of the Option Data
       
   473 	* @param aAlign
       
   474 	*	Option alignment requirement. The default is no alignment.
       
   475 	* @param aModulo
       
   476 	*	Option must start at an octect position which is a multiple
       
   477 	*	of the specified value
       
   478 	*/
       
   479 	{
       
   480 	TUint padlen = aAlign?(TUint(aAlign - 2) % aModulo):0;  //Leading pad
       
   481 	TInt len = 2 + padlen + aOption.Length();
       
   482 	TInt trailpad = (8 - (len & 7)) & 7;
       
   483 	len += trailpad;
       
   484 
       
   485 	TInt ofs;
       
   486 	if (! ExtHdrGetOrAppendL(KProtocolInet6DestinationOptions, ofs, len))
       
   487 		{
       
   488 		//Simple case, new header was allocated and initialized with required length.
       
   489 		//Just put the option in.
       
   490 		ofs += 2;
       
   491 #ifdef OPTIMIZE_PADDING
       
   492 		if (padlen > 1)
       
   493 			{
       
   494 			TInet6Packet<TInet6OptionBase> pad(iPacket, ofs);
       
   495 			if (pad.iHdr == NULL)
       
   496 				User::Leave(KErrGeneral);
       
   497 			pad.iHdr->SetType(KDstOptionPadN);
       
   498 			pad.iHdr->SetDataLen(padlen - 2);
       
   499 			}
       
   500 #endif
       
   501 		ofs += padlen;
       
   502 		iPacket.CopyIn(aOption, ofs);
       
   503 #ifdef OPTIMIZE_PADDING
       
   504 		ofs += aOption.Length();
       
   505 		if (trailpad > 1)
       
   506 			{
       
   507 			TInet6Packet<TInet6OptionBase> pad(iPacket, ofs);
       
   508 			if (pad.iHdr == NULL)
       
   509 				User::Leave(KErrGeneral);
       
   510 			pad.iHdr->SetType(KDstOptionPadN);
       
   511 			pad.iHdr->SetDataLen(trailpad - 2);
       
   512 			}
       
   513 #endif
       
   514 		return;
       
   515 		}
       
   516 
       
   517 	//Now we have the position and size of the header
       
   518 	TInet6Packet<TInet6Options> opt(iPacket, ofs);
       
   519 	if (opt.iHdr == NULL)
       
   520 		User::Leave(KErrGeneral);
       
   521 
       
   522 	//padlen = leading pad
       
   523 	ofs += len;
       
   524 	padlen = aAlign?(TUint(aAlign - ofs) % aModulo):0;
       
   525 	TInt size = padlen + aOption.Length();
       
   526 	trailpad = (8 - (size & 7)) & 7;
       
   527 	size += trailpad;
       
   528 	
       
   529 	RMBufChain pkt;
       
   530 	pkt.AllocL(size);
       
   531 	pkt.FillZ();
       
   532 #ifdef OPTIMIZE_PADDING
       
   533 	//Optimize leading pad
       
   534 	if (padlen > 1)
       
   535 		{
       
   536 		TInet6Packet<TInet6OptionBase> pad(pkt, 0);
       
   537 		if (pad.iHdr == NULL)
       
   538 			User::Leave(KErrGeneral);
       
   539 		pad.iHdr->SetType(KDstOptionPadN);
       
   540 		pad.iHdr->SetDataLen(padlen - 2);
       
   541 		}
       
   542 	//Optimize trailing pad
       
   543 	if (trailpad > 1)
       
   544 		{
       
   545 		TInet6Packet<TInet6OptionBase> pad(pkt, padlen+aOption.Length());
       
   546 		if (pad.iHdr == NULL)
       
   547 			User::Leave(KErrGeneral);
       
   548 		pad.iHdr->SetType(KDstOptionPadN);
       
   549 		pad.iHdr->SetDataLen(trailpad - 2);
       
   550 		}
       
   551 #endif
       
   552 	pkt.CopyIn(aOption, padlen);
       
   553 	
       
   554 	iPacket.Append(pkt);
       
   555 	
       
   556 	iOffset += size;
       
   557 	opt.iHdr->SetHdrExtLen(opt.iHdr->HdrExtLen() + (size >> 3));
       
   558 	}