|
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 // tcp.cpp - TCP protocol for IPv6/IPv4 |
|
15 // |
|
16 |
|
17 #include "tcp.h" |
|
18 #include <icmp6_hdr.h> |
|
19 #include <ip4_hdr.h> |
|
20 #include "tcpip_ini.h" |
|
21 |
|
22 // Copied from ip6.cpp. Should move to some common definition file? |
|
23 static const TLitC8<sizeof(TInt)> KInetOptionDisable = {sizeof(TInt), {0}}; |
|
24 |
|
25 // |
|
26 // TCP Protocol Description |
|
27 // |
|
28 |
|
29 void CProtocolTCP6::Describe(TServerProtocolDesc &aDesc) |
|
30 { |
|
31 aDesc.iName = _S("tcp"); |
|
32 aDesc.iAddrFamily = KAfInet; |
|
33 aDesc.iSockType = KSockStream; |
|
34 aDesc.iProtocol = KProtocolInetTcp; |
|
35 aDesc.iVersion = TVersion(KInet6MajorVersionNumber, |
|
36 KInet6MinorVersionNumber, |
|
37 KInet6BuildVersionNumber); |
|
38 aDesc.iByteOrder = EBigEndian; |
|
39 aDesc.iServiceInfo = KSIStreamBased | KSIInOrder | KSIReliable | |
|
40 KSIGracefulClose | KSIPeekData | KSIUrgentData | |
|
41 KSIRequiresOwnerInfo; |
|
42 aDesc.iNamingServices = KNSNameResolution | KNSRequiresConnectionStartup; |
|
43 aDesc.iSecurity = KSocketNoSecurity; |
|
44 aDesc.iMessageSize = KSocketMessageSizeIsStream; |
|
45 aDesc.iServiceTypeInfo = ESocketSupport | ETransport | EPreferMBufChains | ENeedMBufs | EUseCanSend; |
|
46 aDesc.iNumSockets = KUnlimitedSockets; |
|
47 } |
|
48 |
|
49 |
|
50 |
|
51 CProtocolTCP6::CProtocolTCP6() |
|
52 { |
|
53 __DECLARE_NAME(_S("CProtocolTCP6")); |
|
54 } |
|
55 |
|
56 |
|
57 CProtocolTCP6::~CProtocolTCP6() |
|
58 { |
|
59 LOG(Log::Printf(_L("\ttcp Deleted"))); |
|
60 } |
|
61 |
|
62 CServProviderBase* CProtocolTCP6::NewSAPL(TUint aSockType) |
|
63 { |
|
64 LOG(Log::Printf(_L("NewSAPL\ttcp SockType=%d)"), aSockType)); |
|
65 if (aSockType!=KSockStream) |
|
66 User::Leave(KErrNotSupported); |
|
67 CProviderTCP6 *sap = new (ELeave) CProviderTCP6(this); |
|
68 CleanupStack::PushL(sap); |
|
69 sap->InitL(); |
|
70 CleanupStack::Pop(); |
|
71 LOG(Log::Printf(_L("NewSAPL\ttcp SAP[%u] OK"), (TInt)sap)); |
|
72 return sap; |
|
73 } |
|
74 |
|
75 |
|
76 void CProtocolTCP6::InitL(TDesC& aTag) |
|
77 { |
|
78 CProtocolInet6Transport::InitL(aTag); |
|
79 |
|
80 iRandomIncrement = 0; |
|
81 UserHal::TickPeriod((TTimeIntervalMicroSeconds32&)iClockGranularity); |
|
82 } |
|
83 |
|
84 |
|
85 void CProtocolTCP6::StartL() |
|
86 { |
|
87 CProtocolInet6Transport::StartL(); |
|
88 |
|
89 iMSS = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MSS, |
|
90 KTcpDefaultMSS, KTcpMinimumMSS, 65535, ETrue); |
|
91 |
|
92 iRecvBuf = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RECV_BUF, |
|
93 KTcpDefaultRcvWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue); |
|
94 |
|
95 iSendBuf = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SEND_BUF, |
|
96 KTcpDefaultSndWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue); |
|
97 |
|
98 // Argh: ini is in millisecs, but CProtocolTCP6 member is in microsecs. |
|
99 iMinRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MIN_RTO, |
|
100 KTcpMinRTO/1000, iClockGranularity/1000, KTcpMaxRTO/1000, ETrue) * 1000; |
|
101 |
|
102 iMaxRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MAX_RTO, |
|
103 KTcpMaxRTO/1000, iMinRTO/1000, KTcpMaxRTO/1000, ETrue) * 1000; |
|
104 |
|
105 iInitialRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_INITIAL_RTO, |
|
106 KTcpInitialRTO/1000, iMinRTO/1000, iMaxRTO/1000, ETrue) * 1000; |
|
107 |
|
108 iSrttSmooth = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SRTT_SMOOTH, |
|
109 KTcpSrttSmooth, 1, KMaxTInt, ETrue); |
|
110 |
|
111 iMdevSmooth = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTTVAR_SMOOTH, |
|
112 KTcpMdevSmooth, 1, KMaxTInt, ETrue); |
|
113 |
|
114 iRTO_K = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTO_K, |
|
115 KTcpRTO_K, 1, KMaxTInt, ETrue); |
|
116 |
|
117 iRTO_G = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTO_G, |
|
118 iClockGranularity/1000, iClockGranularity/1000, KMaxTInt, ETrue) * 1000; |
|
119 |
|
120 iMaxBurst = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MAX_BURST, |
|
121 KTcpMaxTransmit, 1, KMaxTInt, ETrue); |
|
122 |
|
123 iAckDelay = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ACK_DELAY, |
|
124 KTcpAckDelay/1000, iClockGranularity/1000, KMaxTInt/1000, ETrue) * 1000; |
|
125 |
|
126 iSynRetries = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SYN_RETRIES, |
|
127 KTcpSynRetries, 0, KMaxTInt, ETrue); |
|
128 |
|
129 iRetries1 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RETRIES1, |
|
130 KTcpMaxRetries1, 0, KMaxTInt, ETrue); |
|
131 |
|
132 iRetries2 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RETRIES2, |
|
133 KTcpMaxRetries2, iRetries1, KMaxTInt, ETrue); |
|
134 |
|
135 iProbeStyle = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_PROBE_STYLE, 2, 0, 2, EFalse); |
|
136 |
|
137 iMsl2Delay = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MSL2, |
|
138 KTcpMsl2Delay/1000, 1, KMaxTInt/1000, ETrue) * 1000; |
|
139 |
|
140 iReordering = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_REORDERING, |
|
141 KTcpReordering, 0, KMaxTInt, ETrue); |
|
142 |
|
143 iInitialCwnd = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_INITIAL_CWND, |
|
144 KTcpInitialCwnd, 0, KMaxTInt, ETrue); |
|
145 |
|
146 iLtxWindow = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_LTX_WINDOW, |
|
147 KTcpLtxWindow, 0, KMaxTInt, ETrue); |
|
148 |
|
149 iKeepAliveIntv = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_KEEPALIVE_INTV, |
|
150 KTcpKeepAliveIntv, 0, KMaxTInt, ETrue); |
|
151 |
|
152 iNumKeepAlives = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_NUM_KEEPALIVES, |
|
153 KTcpNumKeepAlives, 0, KMaxTInt, ETrue); |
|
154 |
|
155 // keepalive retransmission timer cannot be longer than 30 min, because timers are in microseconds. |
|
156 iKeepAliveRxmt = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_KEEPALIVE_RXMT, |
|
157 KTcpKeepAliveRxmt, 0, 1800, ETrue); |
|
158 |
|
159 iFinPersistency = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_FIN_PERSISTENCY, |
|
160 KTcpFinPersistency, 0, iRetries2, ETrue); |
|
161 |
|
162 // ECN settings: 0 = disabled, 1 = enabled with ECT(1), 2 = enabled with ECT(0) |
|
163 iEcn = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ECN, 0, 0, 2, EFalse); |
|
164 |
|
165 iSpuriousRtoResponse = GetIniValue(TCPIP_INI_TCP, |
|
166 TCPIP_INI_TCP_SPURIOUS_RTO_RESPONSE, 1, 1, 3, EFalse); |
|
167 |
|
168 iWinScale = (TInt8)GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_WINSCALE, 0, -1, 7, ETrue); |
|
169 |
|
170 // Flags enabled by default |
|
171 iTimeStamps = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_TIMESTAMPS, 1, 0, 1); |
|
172 iSack = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SACK, 1, 0, 1); |
|
173 iRFC2414 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RFC2414, 1, 0, 1); |
|
174 iDSack = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_DSACK, 1, 0, 1); |
|
175 iFRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_FRTO, 1, 0, 1); |
|
176 |
|
177 // Flags disabled by default |
|
178 iLocalTimeWait = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_LOCAL_TIMEWAIT, 0, 0, 1); |
|
179 iStrictNagle = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_STRICT_NAGLE, 0, 0, 1); |
|
180 iPushAck = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_PUSH_ACK, 0, 0, 1); |
|
181 iAlignOpt = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ALIGNOPT, 0, 0, 1); |
|
182 |
|
183 // Note: 'dstcache' is in [ip] section, because it is not necessarily TCP specific |
|
184 iDstCache = GetIniValue(TCPIP_INI_IP, TCPIP_INI_DSTCACHE, 0, 0, 1); |
|
185 |
|
186 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
187 iTcpMaxRecvWin = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RECV_MAX_WND, |
|
188 KTcpDefaultRcvMaxWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue); |
|
189 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW |
|
190 } |
|
191 |
|
192 |
|
193 void CProtocolTCP6::Identify(TServerProtocolDesc *aInfo) const |
|
194 { |
|
195 Describe(*aInfo); |
|
196 } |
|
197 |
|
198 TInt CProtocolTCP6::Send(RMBufChain& aPacket,CProtocolBase* /*aSourceProtocol=NULL*/) |
|
199 { |
|
200 #ifdef _LOGx |
|
201 RMBufSendPacket seg; |
|
202 seg.Assign(aPacket); |
|
203 RMBufSendInfo *info = seg.Unpack(); |
|
204 LOG(LogPacket('>', seg, info)); |
|
205 seg.Pack(); |
|
206 aPacket.Assign(seg); |
|
207 #endif |
|
208 return iNetwork->Send(aPacket); |
|
209 } |
|
210 |
|
211 void CProtocolTCP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/) |
|
212 { |
|
213 RMBufRecvPacket seg; |
|
214 seg.Assign(aPacket); |
|
215 // RMBufRecvPacket& seg = (RMBufRecvPacket&)aPacket; |
|
216 RMBufRecvInfo* info = seg.Unpack(); |
|
217 |
|
218 #ifdef _LOG |
|
219 TBuf<50> src, dst; |
|
220 LOG(Log::Printf(_L("\ttcp Process(%d bytes)"), seg.Length())); |
|
221 #endif |
|
222 |
|
223 ASSERT(info->iLength == seg.Length()); |
|
224 |
|
225 TTcpPacket pkt; |
|
226 TInet6Packet<TInet6HeaderIP4> ip4; |
|
227 TInet6Packet<TInet6HeaderIP> ip6; |
|
228 TInt err = KErrNone, errMask = MSocketNotify::EErrorAllOperations; |
|
229 CProviderTCP6 *sap; |
|
230 TInetAddr icmpSender; |
|
231 |
|
232 switch (info->iIcmp) |
|
233 { |
|
234 case 0: |
|
235 |
|
236 // Check source and destination addresses |
|
237 if (!(TInetAddr::Cast(info->iDstAddr).IsUnicast() && TInetAddr::Cast(info->iSrcAddr).IsUnicast())) |
|
238 { |
|
239 LOG(Log::Printf(_L("\ttcpProcess() Invalid source or destination address. Packet discarded"))); |
|
240 seg.Free(); |
|
241 break; |
|
242 } |
|
243 |
|
244 pkt.Set(seg, info->iOffset, KTcpMinHeaderLength); |
|
245 |
|
246 // Verify header length. |
|
247 if (!pkt.iHdr || info->iLength < pkt.iHdr->HeaderLength()) |
|
248 { |
|
249 LOG(Log::Printf(_L("\ttcp Process() Invalid header. Packet discarded"))); |
|
250 seg.Free(); |
|
251 return; |
|
252 } |
|
253 |
|
254 // Get port numbers from header |
|
255 info->iSrcAddr.SetPort(pkt.iHdr->SrcPort()); |
|
256 info->iDstAddr.SetPort(pkt.iHdr->DstPort()); |
|
257 |
|
258 #ifdef _LOG |
|
259 LogPacket('<', seg, info, info->iOffset); |
|
260 pkt.Set(seg, info->iOffset, pkt.iHdr->HeaderLength()); // LogPacket() may have realigned the header. |
|
261 #endif |
|
262 |
|
263 // Verify TCP checksum |
|
264 if (!pkt.VerifyChecksum(seg, info, info->iOffset)) |
|
265 { |
|
266 LOG(Log::Printf(_L("\ttcp Process() Bad checksum. Packet discarded"))); |
|
267 seg.Free(); |
|
268 break; |
|
269 } |
|
270 |
|
271 #ifdef _LOGx |
|
272 TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).Output(dst); |
|
273 LOG(Log::Printf(_L("\ttcp Process(%d bytes): {%S,%d} -> {%S,%d}"), |
|
274 seg.Length(), &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port())); |
|
275 #endif |
|
276 |
|
277 // More sanity checking. |
|
278 if (info->iSrcAddr.Port() == KInetPortNone || |
|
279 info->iDstAddr.Port() == KInetPortNone) |
|
280 { |
|
281 LOG(Log::Printf(_L("\ttcp Process() Illegal port number. Packet discarded"))); |
|
282 seg.Free(); |
|
283 break; |
|
284 } |
|
285 |
|
286 sap = (CProviderTCP6*)LocateSap(EMatchServerUnspecAddr, |
|
287 info->iVersion == 4 ? KAfInet : KAfInet6, |
|
288 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
289 info->iDstAddr, info->iSrcAddr); |
|
290 #else |
|
291 info->iDstAddr, info->iSrcAddr, NULL, info->iInterfaceIndex); |
|
292 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
293 if (sap == NULL) |
|
294 { |
|
295 LOG(Log::Printf(_L("\ttcp Process() No socket. Packet discarded"))); |
|
296 if (!pkt.iHdr->RST()) |
|
297 { |
|
298 // |
|
299 // Send RST. |
|
300 // |
|
301 if (NetworkService()->Interfacer()->LocalScope(TInetAddr::Cast(info->iDstAddr).Ip6Address(), |
|
302 info->iInterfaceIndex, EScopeType_IF)) |
|
303 { |
|
304 if (pkt.iHdr->ACK()) |
|
305 { |
|
306 SendControlSegment(NULL, info->iDstAddr, info->iSrcAddr, KTcpCtlRST, |
|
307 pkt.iHdr->Acknowledgment(), 0); |
|
308 } |
|
309 else |
|
310 { |
|
311 //TTcpSeqNum seq = pkt.iHdr->Sequence() + aPacket.Length() - pkt.iHdr->HeaderLength(); |
|
312 TTcpSeqNum seq = pkt.iHdr->Sequence() + seg.Length() - |
|
313 pkt.iHdr->HeaderLength() - info->iOffset; |
|
314 |
|
315 // Adjust for SYN and FIN |
|
316 if (pkt.iHdr->SYN() || pkt.iHdr->FIN()) |
|
317 seq++; |
|
318 |
|
319 SendControlSegment(NULL, info->iDstAddr, info->iSrcAddr, KTcpCtlRST|KTcpCtlACK, 0, seq); |
|
320 } |
|
321 } |
|
322 } |
|
323 seg.Free(); |
|
324 break; |
|
325 } |
|
326 |
|
327 // Bump it to the SAP. |
|
328 seg.Pack(); |
|
329 sap->Process(seg); |
|
330 break; |
|
331 |
|
332 case KProtocolInetIcmp: |
|
333 case KProtocolInet6Icmp: |
|
334 |
|
335 /* From RFC1122: |
|
336 4.2.3.9 ICMP Messages |
|
337 |
|
338 TCP MUST act on an ICMP error message passed up from the IP |
|
339 layer, directing it to the connection that created the |
|
340 error. The necessary demultiplexing information can be |
|
341 found in the IP header contained within the ICMP message. |
|
342 |
|
343 o Source Quench |
|
344 |
|
345 TCP MUST react to a Source Quench by slowing |
|
346 transmission on the connection. The RECOMMENDED |
|
347 procedure is for a Source Quench to trigger a "slow |
|
348 start," as if a retransmission timeout had occurred. |
|
349 |
|
350 o Destination Unreachable -- codes 0, 1, 5 |
|
351 |
|
352 Since these Unreachable messages indicate soft error |
|
353 conditions, TCP MUST NOT abort the connection, and it |
|
354 SHOULD make the information available to the |
|
355 application. |
|
356 |
|
357 DISCUSSION: |
|
358 TCP could report the soft error condition directly |
|
359 to the application layer with an upcall to the |
|
360 ERROR_REPORT routine, or it could merely note the |
|
361 message and report it to the application only when |
|
362 and if the TCP connection times out. |
|
363 |
|
364 o Destination Unreachable -- codes 2-4 |
|
365 |
|
366 These are hard error conditions, so TCP SHOULD abort |
|
367 the connection. |
|
368 |
|
369 o Time Exceeded -- codes 0, 1 |
|
370 |
|
371 This should be handled the same way as Destination |
|
372 Unreachable codes 0, 1, 5 (see above). |
|
373 |
|
374 o Parameter Problem |
|
375 |
|
376 This should be handled the same way as Destination |
|
377 Unreachable codes 0, 1, 5 (see above).*/ |
|
378 |
|
379 // |
|
380 // Map the first 8 bytes of TCP segment header |
|
381 // (8 bytes is all there is in an ICMPv4 packet) |
|
382 // |
|
383 // WARNING!!! Any attempt to access fields other than |
|
384 // SrcPort, DstPort, or Sequence WILL CAUSE |
|
385 // BAD THINGS TO HAPPEN! |
|
386 // |
|
387 // |
|
388 pkt.Set(seg, info->iOffset, 8); |
|
389 if (!pkt.iHdr) |
|
390 { |
|
391 LOG(Log::Printf(_L("\ttcp Process() Invalid TCP header in ICMP"))); |
|
392 seg.Free(); |
|
393 break; |
|
394 } |
|
395 |
|
396 // Get port numbers from header |
|
397 info->iSrcAddr.SetPort(pkt.iHdr->SrcPort()); |
|
398 info->iDstAddr.SetPort(pkt.iHdr->DstPort()); |
|
399 |
|
400 #ifdef _LOG |
|
401 TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst); |
|
402 LOG(Log::Printf(_L("\ttcp Process() ICMP reply to TCP segment {%S,%d} -> {%S,%d}"), |
|
403 &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port())); |
|
404 LOG(Log::Printf(_L("\ttcp Process() ICMP type=%d code=%d param=%d received"), |
|
405 info->iType, info->iCode, info->iParameter)); |
|
406 #endif |
|
407 |
|
408 sap = (CProviderTCP6*)LocateSap(EMatchServerUnspecAddr, |
|
409 info->iVersion == 4 ? KAfInet : KAfInet6, |
|
410 info->iSrcAddr, info->iDstAddr); |
|
411 if (sap == NULL) |
|
412 { |
|
413 LOG(Log::Printf(_L("\ttcp Process() No socket. Discarding ICMP message"))); |
|
414 seg.Free(); |
|
415 break; |
|
416 } |
|
417 |
|
418 if (info->iIcmp == KProtocolInetIcmp) |
|
419 { |
|
420 // |
|
421 // ICMPv4 message processing |
|
422 // |
|
423 ip4.Set(seg, 0, TInet6HeaderIP4::MinHeaderLength()); |
|
424 if (!ip4.iHdr) |
|
425 { |
|
426 LOG(Log::Printf(_L("\ttcp SAP[%u] Invalid IPv4 header in ICMP"), (TInt)sap)); |
|
427 seg.Free(); |
|
428 break; |
|
429 } |
|
430 icmpSender.SetAddress(ip4.iHdr->SrcAddr()); |
|
431 switch (info->iType) |
|
432 { |
|
433 case KInet4ICMP_Unreachable: |
|
434 /* |
|
435 Code 0 = net unreachable |
|
436 1 = host unreachable |
|
437 2 = protocol unreachable |
|
438 3 = port unreachable |
|
439 4 = fragmentation needed and DF set |
|
440 5 = source route failed |
|
441 6 = destination network unknown |
|
442 7 = destination host unknown |
|
443 8 = source host isolated |
|
444 9 = communication with destination network administratively prohibited |
|
445 10 = communication with destination host administratively prohibited |
|
446 11 = network unreachable for type of service |
|
447 12 = host unreachable for type of service |
|
448 */ |
|
449 switch (info->iCode) |
|
450 { |
|
451 case 2: |
|
452 err = KErrNoProtocolOpt; |
|
453 break; |
|
454 |
|
455 case 3: |
|
456 err = KErrCouldNotConnect; |
|
457 break; |
|
458 |
|
459 case 0: // Transient condition |
|
460 errMask = 0; |
|
461 // Fall through |
|
462 |
|
463 case 5: case 6: case 8: case 9: // Persistent conditions |
|
464 err = KErrNetUnreach; |
|
465 break; |
|
466 |
|
467 case 1: // Transient condition |
|
468 errMask = 0; |
|
469 // Fall through |
|
470 |
|
471 case 7: case 10: case 12: // Persistent conditions |
|
472 err = KErrHostUnreach; |
|
473 break; |
|
474 |
|
475 default: |
|
476 break; |
|
477 } |
|
478 break; |
|
479 |
|
480 case KInet4ICMP_SourceQuench: // Do a slow start |
|
481 sap->SourceQuench(); |
|
482 break; |
|
483 |
|
484 case KInet4ICMP_TimeExceeded: |
|
485 err = KErrNetUnreach; |
|
486 errMask = 0; |
|
487 break; |
|
488 |
|
489 case KInet4ICMP_ParameterProblem: |
|
490 err = KErrArgument; |
|
491 errMask = 0; |
|
492 break; |
|
493 |
|
494 default: |
|
495 break; |
|
496 } |
|
497 } |
|
498 else |
|
499 { |
|
500 // |
|
501 // ICMPv6 message processing |
|
502 // |
|
503 ip6.Set(seg, 0, TInet6HeaderIP::MinHeaderLength()); |
|
504 if (!ip6.iHdr) |
|
505 { |
|
506 LOG(Log::Printf(_L("\ttcp SAP[%u] Invalid IPv6 header in ICMP"), (TInt)sap)); |
|
507 seg.Free(); |
|
508 break; |
|
509 } |
|
510 icmpSender.SetAddress(ip6.iHdr->SrcAddr()); |
|
511 switch (info->iType) |
|
512 { |
|
513 case KInet6ICMP_Unreachable: |
|
514 /* |
|
515 Code 0 - no route to destination |
|
516 1 - communication with destination |
|
517 administratively prohibited |
|
518 2 - (not assigned) |
|
519 3 - address unreachable |
|
520 4 - port unreachable |
|
521 */ |
|
522 switch (info->iCode) |
|
523 { |
|
524 case 3: |
|
525 err = KErrHostUnreach; |
|
526 break; |
|
527 |
|
528 case 4: |
|
529 err = KErrCouldNotConnect; |
|
530 break; |
|
531 |
|
532 default: |
|
533 err = KErrNetUnreach; |
|
534 break; |
|
535 } |
|
536 break; |
|
537 |
|
538 case KInet6ICMP_PacketTooBig: |
|
539 // |
|
540 // Treat this as a soft error. The flow should |
|
541 // automatically adjust to changes in path MTU. |
|
542 // |
|
543 err = KErrTooBig; |
|
544 errMask = 0; |
|
545 break; |
|
546 |
|
547 case KInet6ICMP_TimeExceeded: |
|
548 /* |
|
549 Code 0 - hop limit exceeded in transit |
|
550 1 - fragment reassembly time exceeded |
|
551 */ |
|
552 err = KErrNetUnreach; |
|
553 errMask = 0; |
|
554 break; |
|
555 |
|
556 case KInet6ICMP_ParameterProblem: |
|
557 /* |
|
558 Code 0 - erroneous header field encountered |
|
559 1 - unrecognized Next Header type encountered |
|
560 2 - unrecognized IPv6 option encountered |
|
561 */ |
|
562 err = KErrArgument; |
|
563 errMask = 0; |
|
564 break; |
|
565 |
|
566 default: |
|
567 break; |
|
568 } |
|
569 } |
|
570 |
|
571 if (err != KErrNone) |
|
572 { |
|
573 // |
|
574 // TCP only treats ICMP errors as hard errors if it's |
|
575 // setting up a new connection. We make ICMP spoofing |
|
576 // a little bit more difficult by checking the included |
|
577 // TCP sequence number. If the sequence number does not |
|
578 // match, we change the error to a soft error. |
|
579 // |
|
580 if (errMask && pkt.iHdr->Sequence() != sap->iSND.UNA) |
|
581 { |
|
582 LOG(Log::Printf(_L("\ttcp SAP[%u] TCP sequence mismatch. Converting to soft error"), (TInt)sap)); |
|
583 errMask = 0; |
|
584 } |
|
585 |
|
586 LOG(Log::Printf(_L("\ttcp SAP[%u] Reporting ICMP error %d, mask %d.\r\n"), (TInt)sap, err, errMask)); |
|
587 } |
|
588 |
|
589 // Store and report |
|
590 sap->IcmpError(err, errMask, |
|
591 info->iType, info->iCode, |
|
592 TInetAddr::Cast(info->iSrcAddr), |
|
593 TInetAddr::Cast(info->iDstAddr), |
|
594 TInetAddr::Cast(icmpSender)); |
|
595 seg.Free(); |
|
596 break; |
|
597 |
|
598 default: |
|
599 break; |
|
600 } |
|
601 } |
|
602 |
|
603 |
|
604 // |
|
605 // This routine generates and transmits a TCP control segment. |
|
606 // |
|
607 TInt CProtocolTCP6::SendControlSegment(RFlowContext *aFlow, |
|
608 const TSockAddr& aSrcAddr, const TSockAddr& aDstAddr, |
|
609 TUint8 aFlags, TTcpSeqNum aSeq, TTcpSeqNum aAck, |
|
610 TUint32 aWnd, TUint32 aUP) |
|
611 { |
|
612 LOG(Log::Printf(_L("\ttcp SendControlSegment"))); |
|
613 |
|
614 RMBufSendPacket seg; |
|
615 RMBufSendInfo *info = NULL; |
|
616 TInt err; |
|
617 |
|
618 // Reserve space for IP+TCP headers and info. |
|
619 err = seg.Alloc(TInet6HeaderIP::MaxHeaderLength() + KTcpMinHeaderLength, iBufAllocator); |
|
620 if (err != KErrNone) |
|
621 return err; |
|
622 info = seg.NewInfo(); |
|
623 if (!info) |
|
624 { |
|
625 seg.Free(); |
|
626 return KErrNoMBufs; |
|
627 } |
|
628 |
|
629 // Leave space for the IP header. |
|
630 seg.TrimStart(TInet6HeaderIP::MaxHeaderLength()); |
|
631 |
|
632 // Fill in info struct |
|
633 info->iProtocol = KProtocolInetTcp; |
|
634 info->iSrcAddr = aSrcAddr; |
|
635 info->iDstAddr = aDstAddr; |
|
636 info->iLength = KTcpMinHeaderLength; |
|
637 |
|
638 // Open flow context |
|
639 if (aFlow != NULL && aFlow->IsOpen()) |
|
640 { |
|
641 err = info->iFlow.Open(*aFlow, info); |
|
642 } |
|
643 else |
|
644 { |
|
645 if ((err = info->iFlow.Open(NetworkService(), info->iDstAddr, info->iSrcAddr, info->iProtocol)) |
|
646 == KErrNone) |
|
647 { |
|
648 info->iFlow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable); |
|
649 } |
|
650 } |
|
651 |
|
652 if (err != KErrNone) |
|
653 { |
|
654 // If at first you don't succeed... Well, life is sometimes unforgiving. |
|
655 info->iFlow.Close(); |
|
656 seg.Free(); |
|
657 return err; |
|
658 } |
|
659 |
|
660 // |
|
661 // Fill in TCP header. Note that the header length has already |
|
662 // been set and the checksum will be calculated later. |
|
663 // |
|
664 TTcpPacket pkt(seg); |
|
665 pkt.iHdr->SetHeaderLength(KTcpMinHeaderLength); |
|
666 pkt.iHdr->SetSrcPort(info->iSrcAddr.Port()); |
|
667 pkt.iHdr->SetDstPort(info->iDstAddr.Port()); |
|
668 pkt.iHdr->SetSequence(aSeq); |
|
669 pkt.iHdr->SetAcknowledgment(aAck); |
|
670 pkt.iHdr->SetControl(aFlags); |
|
671 pkt.iHdr->SetWindow(aWnd); |
|
672 pkt.iHdr->SetUrgent(aUP); |
|
673 |
|
674 ASSERT(info->iLength == seg.Length()); |
|
675 |
|
676 // |
|
677 // Compute checksum and send the segment. |
|
678 // |
|
679 pkt.ComputeChecksum(seg, info); |
|
680 LOG(LogPacket('>', seg, info)); |
|
681 seg.Pack(); |
|
682 Send(seg); |
|
683 |
|
684 return KErrNone; |
|
685 } |
|
686 |
|
687 |
|
688 TUint32 CProtocolTCP6::RandomSequence() |
|
689 { |
|
690 iRandomIncrement += Random(1000000); |
|
691 return ((User::TickCount() * iClockGranularity) >> 2) + iRandomIncrement; |
|
692 } |
|
693 |
|
694 |
|
695 #ifdef _LOG |
|
696 void CProtocolTCP6::LogPacket(char aDir, RMBufChain& aPacket, RMBufPktInfo *info, TInt aOffset) |
|
697 { |
|
698 RMBufPacketBase pkt; |
|
699 pkt.Assign(aPacket); |
|
700 TBool packed = EFalse; |
|
701 |
|
702 if (info == NULL) |
|
703 { |
|
704 info = pkt.Unpack(); |
|
705 packed = ETrue; |
|
706 } |
|
707 |
|
708 TBuf<0x100> output; |
|
709 TBuf<50> src, dst; |
|
710 TTcpPacket seg(pkt, aOffset); |
|
711 TTcpSeqNum seq = seg.iHdr->Sequence(); |
|
712 TUint32 len = info->iLength - seg.iHdr->HeaderLength() - aOffset; |
|
713 TTcpOptions opt; |
|
714 TTime now; |
|
715 now.UniversalTime(); |
|
716 #ifdef I64LOW |
|
717 TUint32 usec = I64LOW(now.Int64()); |
|
718 #else |
|
719 TUint32 usec = now.Int64().GetTInt(); |
|
720 #endif |
|
721 |
|
722 TInetAddr(info->iSrcAddr).OutputWithScope(src); |
|
723 TInetAddr(info->iDstAddr).OutputWithScope(dst); |
|
724 |
|
725 output.Format(_L("\t%6u.%03u "), |
|
726 usec / 1000000, (usec / 1000) % 1000); |
|
727 |
|
728 if (aDir == '>') |
|
729 output.AppendFormat(_L("%S.%u > %S.%u"), |
|
730 &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port()); |
|
731 else |
|
732 output.AppendFormat(_L("%S.%u < %S.%u"), |
|
733 &dst, info->iDstAddr.Port(), &src, info->iSrcAddr.Port()); |
|
734 |
|
735 _LIT(KHdrSyn, "S"); |
|
736 _LIT(KHdrFin, "F"); |
|
737 _LIT(KHdrPsh, "P"); |
|
738 _LIT(KHdrRst, "R"); |
|
739 _LIT(KHdrEce, "E"); |
|
740 _LIT(KHdrCwr, "W"); |
|
741 _LIT(KHdrDot, "."); |
|
742 _LIT(KHdrNot, ""); |
|
743 |
|
744 output.AppendFormat(_L(" %S%S%S%S%S%S%S %u:%u(%u) wnd=%u"), |
|
745 seg.iHdr->SYN() ? &KHdrSyn : &KHdrNot, |
|
746 seg.iHdr->FIN() ? &KHdrFin : &KHdrNot, |
|
747 seg.iHdr->PSH() ? &KHdrPsh : &KHdrNot, |
|
748 seg.iHdr->RST() ? &KHdrRst : &KHdrNot, |
|
749 seg.iHdr->ECE() ? &KHdrEce : &KHdrNot, |
|
750 seg.iHdr->CWR() ? &KHdrCwr : &KHdrNot, |
|
751 !(seg.iHdr->Control() & ~KTcpCtlACK) ? &KHdrDot : &KHdrNot, |
|
752 seq.Uint32(), (seq+len).Uint32(), len, seg.iHdr->Window()); |
|
753 |
|
754 if (seg.iHdr->ACK()) |
|
755 output.AppendFormat(_L(" ack=%u"), (seg.iHdr->Acknowledgment()).Uint32() ); |
|
756 |
|
757 if (seg.iHdr->URG()) |
|
758 output.AppendFormat(_L(" urg=%u"), seg.iHdr->Urgent()); |
|
759 |
|
760 // output.AppendFormat(_L("\r\n")); |
|
761 Log::Write(output); |
|
762 |
|
763 if (seg.iHdr->Options(opt) && opt.Length() > 0) |
|
764 { |
|
765 TUint32 tsVal, tsEcr; |
|
766 TInt blockCount = opt.SackBlocks().Count(); |
|
767 output.Format(_L("\t options [")); |
|
768 if (opt.MSS() >= 0) |
|
769 output.AppendFormat(_L(" MSS=%u"), opt.MSS()); |
|
770 if (opt.SackOk()) |
|
771 output.AppendFormat(_L(" SackOk")); |
|
772 if (opt.TimeStamps(tsVal, tsEcr)) |
|
773 output.AppendFormat(_L(" TS=%u,%u"), tsVal, tsEcr); |
|
774 if (opt.WindowScale()) |
|
775 output.AppendFormat(_L(" WS=%d"), opt.WindowScale()-1); |
|
776 |
|
777 if (blockCount) |
|
778 { |
|
779 SequenceBlockQueueIter iter(opt.SackBlocks()); |
|
780 SequenceBlock *block; |
|
781 |
|
782 output.Append(_L(" SACK=")); |
|
783 iter.SetToFirst(); |
|
784 while (block = iter++, block != NULL) |
|
785 output.AppendFormat(_L("%u-%u%s"), |
|
786 (block->iLeft).Uint32(), |
|
787 (block->iRight).Uint32(), --blockCount ? "," : ""); |
|
788 } |
|
789 output.AppendFormat(_L(" ]")); |
|
790 Log::Write(output); |
|
791 } |
|
792 |
|
793 if (packed) |
|
794 pkt.Pack(); |
|
795 |
|
796 aPacket.Assign(pkt); |
|
797 } |
|
798 #endif |
|
799 |