VirtualBox

source: vbox/trunk/include/VBox/vmm/pdmnetinline.h@ 76585

Last change on this file since 76585 was 76585, checked in by vboxsync, 6 years ago

*: scm --fix-header-guard-endif

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