VirtualBox

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

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

OSE header fixes

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

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