VirtualBox

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

Last change on this file since 30670 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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