VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NetLib/VBoxNetInt.cpp@ 25081

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

SUP,*: API cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.6 KB
Line 
1
2
3/*******************************************************************************
4* Header Files *
5*******************************************************************************/
6#include "VBoxNetLib.h"
7#include <VBox/intnet.h>
8
9/**
10 * Flushes the send buffer.
11 *
12 * @returns VBox status code.
13 * @param pSession The support driver session.
14 * @param hIf The interface handle to flush.
15 */
16int VBoxNetIntIfFlush(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf)
17{
18 INTNETIFSENDREQ SendReq;
19 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
20 SendReq.Hdr.cbReq = sizeof(SendReq);
21 SendReq.pSession = pSession;
22 SendReq.hIf = hIf;
23 return SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
24}
25
26
27/**
28 * Copys the SG segments into the specified fram.
29 *
30 * @param pvFrame The frame buffer.
31 * @param cSegs The number of segments.
32 * @param paSegs The segments.
33 */
34static void vboxnetIntIfCopySG(void *pvFrame, size_t cSegs, PCINTNETSEG paSegs)
35{
36 uint8_t *pbDst = (uint8_t *)pvFrame;
37 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
38 {
39 memcpy(pbDst, paSegs[iSeg].pv, paSegs[iSeg].cb);
40 pbDst += paSegs[iSeg].cb;
41 }
42}
43
44
45/**
46 * Writes a frame packet to the buffer.
47 *
48 * @returns VBox status code.
49 * @param pBuf The buffer.
50 * @param pRingBuf The ring buffer to read from.
51 * @param cSegs The number of segments.
52 * @param paSegs The segments.
53 * @remark This is the same as INTNETRingWriteFrame and
54 * drvIntNetRingWriteFrame.
55 */
56int VBoxNetIntIfRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, size_t cSegs, PCINTNETSEG paSegs)
57{
58 /*
59 * Validate input.
60 */
61 Assert(pBuf);
62 Assert(pRingBuf);
63 uint32_t offWrite = pRingBuf->offWrite;
64 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
65 uint32_t offRead = pRingBuf->offRead;
66 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
67 AssertPtr(paSegs);
68 Assert(cSegs > 0);
69
70 /* Calc frame size. */
71 uint32_t cbFrame = 0;
72 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
73 cbFrame += paSegs[iSeg].cb;
74
75 Assert(cbFrame >= sizeof(RTMAC) * 2);
76
77
78 const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
79 if (offRead <= offWrite)
80 {
81 /*
82 * Try fit it all before the end of the buffer.
83 */
84 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
85 {
86 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
87 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
88 pHdr->cbFrame = cbFrame;
89 pHdr->offFrame = sizeof(INTNETHDR);
90
91 vboxnetIntIfCopySG(pHdr + 1, cSegs, paSegs);
92
93 offWrite += cb + sizeof(INTNETHDR);
94 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
95 if (offWrite >= pRingBuf->offEnd)
96 offWrite = pRingBuf->offStart;
97 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
98 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
99 return VINF_SUCCESS;
100 }
101
102 /*
103 * Try fit the frame at the start of the buffer.
104 * (The header fits before the end of the buffer because of alignment.)
105 */
106 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
107 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
108 {
109 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
110 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
111 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
112 pHdr->cbFrame = cbFrame;
113 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
114
115 vboxnetIntIfCopySG(pvFrameOut, cSegs, paSegs);
116
117 offWrite = pRingBuf->offStart + cb;
118 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
119 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
120 return VINF_SUCCESS;
121 }
122 }
123 /*
124 * The reader is ahead of the writer, try fit it into that space.
125 */
126 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
127 {
128 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
129 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
130 pHdr->cbFrame = cbFrame;
131 pHdr->offFrame = sizeof(INTNETHDR);
132
133 vboxnetIntIfCopySG(pHdr + 1, cSegs, paSegs);
134
135 offWrite += cb + sizeof(INTNETHDR);
136 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
137 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
138 return VINF_SUCCESS;
139 }
140
141 /* (it didn't fit) */
142 /** @todo stats */
143 return VERR_BUFFER_OVERFLOW;
144}
145
146
147/**
148 * Sends a frame
149 *
150 * @returns VBox status code.
151 * @param pSession The support driver session.
152 * @param hIf The interface handle.
153 * @param pBuf The interface buffer.
154 * @param cSegs The number of segments.
155 * @param paSegs The segments.
156 */
157int VBoxNetIntIfSend(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf, size_t cSegs, PCINTNETSEG paSegs)
158{
159 int rc = VBoxNetIntIfRingWriteFrame(pBuf, &pBuf->Send, RT_ELEMENTS(aSegs), &aSegs[0]);
160 if (rc == VERR_BUFFER_OVERFLOW)
161 {
162 VBoxNetIntIfFlush(pSession, hIf);
163 rc = VBoxNetIntIfRingWriteFrame(pBuf, &pBuf->Send, RT_ELEMENTS(aSegs), &aSegs[0]);
164 }
165 if (RT_SUCCESS(rc) && fFlush)
166 rc = VBoxNetIntIfFlush(pSession, hIf);
167 return rc;
168}
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