VirtualBox

source: vbox/trunk/include/VBox/pdmnetinline.h@ 31272

Last change on this file since 31272 was 31272, checked in by vboxsync, 14 years ago

RTNETCSUMTYPE -> PDMNETCSUMTYPE. Assert on invalid parameters.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: pdmnetinline.h 31272 2010-08-02 09:11:22Z vboxsync $ */
2/** @file
3 * PDM - Networking Helpers, Inlined Code. (DEV,++)
4 *
5 * This is all inlined because it's too tedious to create 2-3 libraries to
6 * contain it all (same bad excuse as for intnetinline.h).
7 */
8
9/*
10 * Copyright (C) 2010 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 */
29
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <VBox/log.h>
35#include <VBox/types.h>
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/net.h>
39#include <iprt/string.h>
40
41
42/**
43 * Checksum type.
44 */
45typedef enum PDMNETCSUMTYPE
46{
47 /** No checksum. */
48 PDMNETCSUMTYPE_NONE = 0,
49 /** Normal TCP checksum. */
50 PDMNETCSUMTYPE_COMPLETE,
51 /** Checksum on pseudo header (used with GSO). */
52 PDMNETCSUMTYPE_PSEUDO,
53 /** The usual 32-bit hack. */
54 PDMNETCSUMTYPE_32_BIT_HACK = 0x7fffffff
55} PDMNETCSUMTYPE;
56
57
58/**
59 * Validates the GSO context.
60 *
61 * @returns true if valid, false if not (not asserted or logged).
62 * @param pGso The GSO context.
63 * @param cbGsoMax The max size of the GSO context.
64 * @param cbFrame The max size of the GSO frame (use to validate
65 * the MSS).
66 */
67DECLINLINE(bool) PDMNetGsoIsValid(PCPDMNETWORKGSO pGso, size_t cbGsoMax, size_t cbFrame)
68{
69 PDMNETWORKGSOTYPE enmType;
70
71 if (RT_UNLIKELY(cbGsoMax < sizeof(*pGso)))
72 return false;
73
74 enmType = (PDMNETWORKGSOTYPE)pGso->u8Type;
75 if (RT_UNLIKELY( enmType <= PDMNETWORKGSOTYPE_INVALID || enmType >= PDMNETWORKGSOTYPE_END ))
76 return false;
77
78 /* all types requires both headers. */
79 if (RT_UNLIKELY( pGso->offHdr1 < sizeof(RTNETETHERHDR) ))
80 return false;
81 if (RT_UNLIKELY( pGso->offHdr2 <= pGso->offHdr1 ))
82 return false;
83 if (RT_UNLIKELY( pGso->cbHdrs <= pGso->offHdr2 ))
84 return false;
85
86 /* min size of the 1st header(s). */
87 switch (enmType)
88 {
89 case PDMNETWORKGSOTYPE_IPV4_TCP:
90 case PDMNETWORKGSOTYPE_IPV4_UDP:
91 if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN ))
92 return false;
93 break;
94 case PDMNETWORKGSOTYPE_IPV6_TCP:
95 case PDMNETWORKGSOTYPE_IPV6_UDP:
96 if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV6_MIN_LEN ))
97 return false;
98 break;
99 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
100 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
101 if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN ))
102 return false;
103 break;
104 case PDMNETWORKGSOTYPE_INVALID:
105 case PDMNETWORKGSOTYPE_END:
106 break;
107 /* no default case! want gcc warnings. */
108 }
109
110 /* min size of the 2nd header. */
111 switch (enmType)
112 {
113 case PDMNETWORKGSOTYPE_IPV4_TCP:
114 case PDMNETWORKGSOTYPE_IPV6_TCP:
115 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
116 if (RT_UNLIKELY( (unsigned)pGso->cbHdrs - pGso->offHdr2 < RTNETTCP_MIN_LEN ))
117 return false;
118 break;
119 case PDMNETWORKGSOTYPE_IPV4_UDP:
120 case PDMNETWORKGSOTYPE_IPV6_UDP:
121 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
122 if (RT_UNLIKELY( (unsigned)pGso->cbHdrs - pGso->offHdr2 < RTNETUDP_MIN_LEN ))
123 return false;
124 break;
125 case PDMNETWORKGSOTYPE_INVALID:
126 case PDMNETWORKGSOTYPE_END:
127 break;
128 /* no default case! want gcc warnings. */
129 }
130
131 /* There must be at more than one segment. */
132 if (RT_UNLIKELY( cbFrame <= pGso->cbHdrs ))
133 return false;
134 if (RT_UNLIKELY( cbFrame - pGso->cbHdrs < pGso->cbMaxSeg ))
135 return false;
136
137 return true;
138}
139
140
141/**
142 * Calculates the number of segments a GSO frame will be segmented into.
143 *
144 * @returns Segment count.
145 * @param pGso The GSO context.
146 * @param cbFrame The GSO frame size (header proto + payload).
147 */
148DECLINLINE(uint32_t) PDMNetGsoCalcSegmentCount(PCPDMNETWORKGSO pGso, size_t cbFrame)
149{
150 size_t cbPayload;
151 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame));
152 cbPayload = cbFrame - pGso->cbHdrs;
153 return (uint32_t)((cbPayload + pGso->cbMaxSeg - 1) / pGso->cbMaxSeg);
154}
155
156
157/**
158 * Used to find the IPv6 header when handling 4to6 tunneling.
159 *
160 * @returns Offset of the IPv6 header.
161 * @param pbSegHdrs The headers / frame start.
162 * @param offIpHdr The offset of the IPv4 header.
163 */
164DECLINLINE(uint8_t) pgmNetGsoCalcIpv6Offset(uint8_t *pbSegHdrs, uint8_t offIPv4Hdr)
165{
166 PCRTNETIPV4 pIPv4Hdr = (PCRTNETIPV4)&pbSegHdrs[offIPv4Hdr];
167 return offIPv4Hdr + pIPv4Hdr->ip_hl * 4;
168}
169
170
171/**
172 * Update an UDP header after carving out a segment
173 *
174 * @param u32PseudoSum The pseudo checksum.
175 * @param pbSegHdrs Pointer to the header bytes / frame start.
176 * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header.
177 * @param pbPayload Pointer to the payload bytes.
178 * @param cbPayload The amount of payload.
179 * @param cbHdrs The size of all the headers.
180 * @param enmCsumType Whether to checksum the payload, the pseudo
181 * header or nothing.
182 * @internal
183 */
184DECLINLINE(void) pdmNetGsoUpdateUdpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offUdpHdr,
185 uint8_t const *pbPayload, uint32_t cbPayload, uint8_t cbHdrs,
186 PDMNETCSUMTYPE enmCsumType)
187{
188 PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr];
189 pUdpHdr->uh_ulen = cbPayload + cbHdrs - offUdpHdr;
190 switch (enmCsumType)
191 {
192 case PDMNETCSUMTYPE_NONE:
193 pUdpHdr->uh_sum = 0;
194 break;
195 case PDMNETCSUMTYPE_COMPLETE:
196 pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pUdpHdr);
197 break;
198 /** @todo: Implement:
199 case PDMNETCSUMTYPE_PSEUDO:
200 pUdpHdr->uh_sum = ???;
201 break; */
202 default:
203 AssertFailed();
204 break;
205 }
206}
207
208
209/**
210 * Update a TCP header after carving out a segment.
211 *
212 * @param u32PseudoSum The pseudo checksum.
213 * @param pbSegHdrs Pointer to the header bytes / frame start.
214 * @param offTcpHdr The offset into @a pbSegHdrs of the TCP header.
215 * @param pbPayload Pointer to the payload bytes.
216 * @param cbPayload The amount of payload.
217 * @param offPayload The offset into the payload that we're splitting
218 * up. We're ASSUMING that the payload follows
219 * immediately after the TCP header w/ options.
220 * @param cbHdrs The size of all the headers.
221 * @param fLastSeg Set if this is the last segment.
222 * @param enmCsumType Whether to checksum the payload, the pseudo
223 * header or nothing.
224 * @internal
225 */
226DECLINLINE(void) pdmNetGsoUpdateTcpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offTcpHdr,
227 uint8_t const *pbPayload, uint32_t cbPayload, uint32_t offPayload, uint8_t cbHdrs,
228 bool fLastSeg, PDMNETCSUMTYPE enmCsumType)
229{
230 PRTNETTCP pTcpHdr = (PRTNETTCP)&pbSegHdrs[offTcpHdr];
231 pTcpHdr->th_seq = RT_H2N_U32(RT_N2H_U32(pTcpHdr->th_seq) + offPayload);
232 if (!fLastSeg)
233 pTcpHdr->th_flags &= ~(RTNETTCP_F_FIN | RTNETTCP_F_PSH);
234 switch (enmCsumType)
235 {
236 case PDMNETCSUMTYPE_NONE:
237 pTcpHdr->th_sum = 0;
238 break;
239 case PDMNETCSUMTYPE_COMPLETE:
240 pTcpHdr->th_sum = RTNetTCPChecksum(u32PseudoSum, pTcpHdr, pbPayload, cbPayload);
241 break;
242 case PDMNETCSUMTYPE_PSEUDO:
243 pTcpHdr->th_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum);
244 break;
245 default:
246 AssertFailed();
247 break;
248 }
249}
250
251
252/**
253 * Updates a IPv6 header after carving out a segment.
254 *
255 * @returns 32-bit intermediary checksum value for the pseudo header.
256 * @param pbSegHdrs Pointer to the header bytes.
257 * @param offIpHdr The offset into @a pbSegHdrs of the IP header.
258 * @param cbSegPayload The amount of segmented payload. Not to be
259 * confused with the IP payload.
260 * @param cbHdrs The size of all the headers.
261 * @param offPktHdr Offset of the protocol packet header. For the
262 * pseudo header checksum calulation.
263 * @param bProtocol The protocol type. For the pseudo header.
264 * @internal
265 */
266DECLINLINE(uint32_t) pdmNetGsoUpdateIPv6Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, uint8_t cbHdrs,
267 uint8_t offPktHdr, uint8_t bProtocol)
268{
269 PRTNETIPV6 pIpHdr = (PRTNETIPV6)&pbSegHdrs[offIpHdr];
270 uint16_t cbPayload = (uint16_t)(cbHdrs - (offIpHdr + sizeof(RTNETIPV6)) + cbSegPayload);
271 pIpHdr->ip6_plen = RT_H2N_U16(cbPayload);
272 return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)(cbHdrs - offPktHdr + cbSegPayload));
273}
274
275
276/**
277 * Updates a IPv4 header after carving out a segment.
278 *
279 * @returns 32-bit intermediary checksum value for the pseudo header.
280 * @param pbSegHdrs Pointer to the header bytes.
281 * @param offIpHdr The offset into @a pbSegHdrs of the IP header.
282 * @param cbSegPayload The amount of segmented payload.
283 * @param iSeg The segment index.
284 * @param cbHdrs The size of all the headers.
285 * @internal
286 */
287DECLINLINE(uint32_t) pdmNetGsoUpdateIPv4Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload,
288 uint32_t iSeg, uint8_t cbHdrs)
289{
290 PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr];
291 pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload);
292 pIpHdr->ip_id = RT_H2N_U16(RT_N2H_U16(pIpHdr->ip_id) + iSeg);
293 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr);
294 return RTNetIPv4PseudoChecksum(pIpHdr);
295}
296
297
298/**
299 * Carves out the specified segment in a destructive manner.
300 *
301 * This is for sequentially carving out segments and pushing them along for
302 * processing or sending. To avoid allocating a temporary buffer for
303 * constructing the segment in, we trash the previous frame by putting the
304 * header at the end of it.
305 *
306 * @returns Pointer to the segment frame that we've carved out.
307 * @param pGso The GSO context data.
308 * @param pbFrame Pointer to the GSO frame.
309 * @param cbFrame The size of the GSO frame.
310 * @param pbHdrScatch Pointer to a pGso->cbHdrs sized area where we
311 * can save the original header prototypes on the
312 * first call (@a iSeg is 0) and retrieve it on
313 * susequent calls. (Just use a 256 bytes
314 * buffer to make life easy.)
315 * @param iSeg The segment that we're carving out (0-based).
316 * @param cSegs The number of segments in the GSO frame. Use
317 * PDMNetGsoCalcSegmentCount to find this.
318 * @param pcbSegFrame Where to return the size of the returned segment
319 * frame.
320 */
321DECLINLINE(void *) PDMNetGsoCarveSegmentQD(PCPDMNETWORKGSO pGso, uint8_t *pbFrame, size_t cbFrame, uint8_t *pbHdrScatch,
322 uint32_t iSeg, uint32_t cSegs, uint32_t *pcbSegFrame)
323{
324 /*
325 * Figure out where the payload is and where the header starts before we
326 * do the protocol specific carving.
327 */
328 uint8_t * const pbSegHdrs = pbFrame + pGso->cbMaxSeg * iSeg;
329 uint8_t * const pbSegPayload = pbSegHdrs + pGso->cbHdrs;
330 uint32_t const cbSegPayload = iSeg + 1 != cSegs
331 ? pGso->cbMaxSeg
332 : (uint32_t)(cbFrame - iSeg * pGso->cbMaxSeg - pGso->cbHdrs);
333 uint32_t const cbSegFrame = cbSegPayload + pGso->cbHdrs;
334
335 /*
336 * Check assumptions (doing it after declaring the variables because of C).
337 */
338 Assert(iSeg < cSegs);
339 Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame));
340 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame));
341
342 /*
343 * Copy the header and do the protocol specific massaging of it.
344 */
345 if (iSeg != 0)
346 memcpy(pbSegHdrs, pbHdrScatch, pGso->cbHdrs);
347 else
348 memcpy(pbHdrScatch, pbSegHdrs, pGso->cbHdrs);
349
350 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
351 {
352 case PDMNETWORKGSOTYPE_IPV4_TCP:
353 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs),
354 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
355 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
356 break;
357 case PDMNETWORKGSOTYPE_IPV4_UDP:
358 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs),
359 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
360 break;
361 case PDMNETWORKGSOTYPE_IPV6_TCP:
362 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
363 pGso->offHdr2, RTNETIPV4_PROT_TCP),
364 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
365 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
366 break;
367 case PDMNETWORKGSOTYPE_IPV6_UDP:
368 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
369 pGso->offHdr2, RTNETIPV4_PROT_UDP),
370 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
371 break;
372 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
373 pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
374 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
375 cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP),
376 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
377 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
378 break;
379 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
380 pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
381 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
382 cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP),
383 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
384 break;
385 case PDMNETWORKGSOTYPE_INVALID:
386 case PDMNETWORKGSOTYPE_END:
387 /* no default! wnat gcc warnings. */
388 break;
389 }
390
391 *pcbSegFrame = cbSegFrame;
392 return pbSegHdrs;
393}
394
395
396/**
397 * Carves out the specified segment in a non-destructive manner.
398 *
399 * The segment headers and segment payload is kept separate here. The GSO frame
400 * is still expected to be one linear chunk of data, but we don't modify any of
401 * it.
402 *
403 * @returns The offset into the GSO frame of the payload.
404 * @param pGso The GSO context data.
405 * @param pbFrame Pointer to the GSO frame. Used for retriving
406 * the header prototype and for checksumming the
407 * payload. The buffer is not modified.
408 * @param cbFrame The size of the GSO frame.
409 * @param iSeg The segment that we're carving out (0-based).
410 * @param cSegs The number of segments in the GSO frame. Use
411 * PDMNetGsoCalcSegmentCount to find this.
412 * @param pbSegHdrs Where to return the headers for the segment
413 * that's been carved out. The buffer must be at
414 * least pGso->cbHdrs in size, using a 256 byte
415 * buffer is a recommended simplification.
416 * @param pcbSegPayload Where to return the size of the returned
417 * segment payload.
418 */
419DECLINLINE(uint32_t) PDMNetGsoCarveSegment(PCPDMNETWORKGSO pGso, const uint8_t *pbFrame, size_t cbFrame,
420 uint32_t iSeg, uint32_t cSegs, uint8_t *pbSegHdrs, uint32_t *pcbSegPayload)
421{
422 /*
423 * Figure out where the payload is and where the header starts before we
424 * do the protocol specific carving.
425 */
426 uint8_t const * const pbSegPayload = pbFrame + pGso->cbHdrs + iSeg * pGso->cbMaxSeg;
427 uint32_t const cbSegPayload = iSeg + 1 != cSegs
428 ? pGso->cbMaxSeg
429 : (uint32_t)(cbFrame - iSeg * pGso->cbMaxSeg - pGso->cbHdrs);
430
431 /*
432 * Check assumptions (doing it after declaring the variables because of C).
433 */
434 Assert(iSeg < cSegs);
435 Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame));
436 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame));
437
438 /*
439 * Copy the header and do the protocol specific massaging of it.
440 */
441 memcpy(pbSegHdrs, pbFrame, pGso->cbHdrs);
442
443 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
444 {
445 case PDMNETWORKGSOTYPE_IPV4_TCP:
446 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs),
447 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
448 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
449 break;
450 case PDMNETWORKGSOTYPE_IPV4_UDP:
451 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs),
452 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
453 break;
454 case PDMNETWORKGSOTYPE_IPV6_TCP:
455 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
456 pGso->offHdr2, RTNETIPV4_PROT_TCP),
457 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
458 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
459 break;
460 case PDMNETWORKGSOTYPE_IPV6_UDP:
461 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
462 pGso->offHdr2, RTNETIPV4_PROT_UDP),
463 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
464 break;
465 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
466 pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
467 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
468 cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP),
469 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
470 pGso->cbHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE);
471 break;
472 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
473 pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
474 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
475 cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP),
476 pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs, PDMNETCSUMTYPE_COMPLETE);
477 break;
478 case PDMNETWORKGSOTYPE_INVALID:
479 case PDMNETWORKGSOTYPE_END:
480 /* no default! wnat gcc warnings. */
481 break;
482 }
483
484 *pcbSegPayload = cbSegPayload;
485 return pGso->cbHdrs + iSeg * pGso->cbMaxSeg;
486}
487
488
489/**
490 * Prepares the GSO frame for direct use without any segmenting.
491 *
492 * @param pGso The GSO context.
493 * @param pvFrame The frame to prepare.
494 * @param cbFrame The frame size.
495 * @param enmCsumType Whether to checksum the payload, the pseudo
496 * header or nothing.
497 */
498DECLINLINE(void) PDMNetGsoPrepForDirectUse(PCPDMNETWORKGSO pGso, void *pvFrame, size_t cbFrame, PDMNETCSUMTYPE enmCsumType)
499{
500 /*
501 * Figure out where the payload is and where the header starts before we
502 * do the protocol bits.
503 */
504 uint8_t * const pbHdrs = (uint8_t *)pvFrame;
505 uint8_t * const pbPayload = pbHdrs + pGso->cbHdrs;
506 uint32_t const cbFrame32 = (uint32_t)cbFrame;
507 uint32_t const cbPayload = cbFrame32 - pGso->cbHdrs;
508
509 /*
510 * Check assumptions (doing it after declaring the variables because of C).
511 */
512 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame));
513
514 /*
515 * Get down to busienss.
516 */
517 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
518 {
519 case PDMNETWORKGSOTYPE_IPV4_TCP:
520 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrs, 0, pGso->cbHdrs),
521 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrs, true, enmCsumType);
522 break;
523 case PDMNETWORKGSOTYPE_IPV4_UDP:
524 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrs, 0, pGso->cbHdrs),
525 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrs, enmCsumType);
526 break;
527 case PDMNETWORKGSOTYPE_IPV6_TCP:
528 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrs,
529 pGso->offHdr2, RTNETIPV4_PROT_TCP),
530 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrs, true, enmCsumType);
531 break;
532 case PDMNETWORKGSOTYPE_IPV6_UDP:
533 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrs,
534 pGso->offHdr2, RTNETIPV4_PROT_UDP),
535 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrs, enmCsumType);
536 break;
537 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
538 pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrs);
539 pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1),
540 cbPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP),
541 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrs, true, enmCsumType);
542 break;
543 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
544 pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrs);
545 pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1),
546 cbPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP),
547 pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrs, enmCsumType);
548 break;
549 case PDMNETWORKGSOTYPE_INVALID:
550 case PDMNETWORKGSOTYPE_END:
551 /* no default! wnat gcc warnings. */
552 break;
553 }
554}
555
556
557/**
558 * Gets the GSO type name string.
559 *
560 * @returns Pointer to read only name string.
561 * @param enmType The type.
562 */
563DECLINLINE(const char *) PDMNetGsoTypeName(PDMNETWORKGSOTYPE enmType)
564{
565 switch (enmType)
566 {
567 case PDMNETWORKGSOTYPE_IPV4_TCP: return "TCPv4";
568 case PDMNETWORKGSOTYPE_IPV6_TCP: return "TCPv6";
569 case PDMNETWORKGSOTYPE_IPV4_UDP: return "UDPv4";
570 case PDMNETWORKGSOTYPE_IPV6_UDP: return "UDPv6";
571 case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: return "4to6TCP";
572 case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: return "4to6UDP";
573 case PDMNETWORKGSOTYPE_INVALID: return "invalid";
574 case PDMNETWORKGSOTYPE_END: return "end";
575 }
576 return "bad-gso-type";
577}
578
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette