VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp@ 19255

Last change on this file since 19255 was 19255, checked in by vboxsync, 16 years ago

Backed out 46655-57 for now

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.6 KB
Line 
1/* $Id: VBoxNetIntIf.cpp 19255 2009-04-29 10:14:59Z vboxsync $ */
2/** @file
3 * VBoxNetIntIf - IntNet Interface Client Routines.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEFAULT
26#include "VBoxNetLib.h"
27#include <VBox/intnet.h>
28#include <VBox/sup.h>
29#include <VBox/vmm.h>
30#include <VBox/err.h>
31#include <VBox/log.h>
32
33#include <iprt/string.h>
34
35
36
37/**
38 * Flushes the send buffer.
39 *
40 * @returns VBox status code.
41 * @param pSession The support driver session.
42 * @param hIf The interface handle to flush.
43 */
44int VBoxNetIntIfFlush(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf)
45{
46 INTNETIFSENDREQ SendReq;
47 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
48 SendReq.Hdr.cbReq = sizeof(SendReq);
49 SendReq.pSession = pSession;
50 SendReq.hIf = hIf;
51 return SUPCallVMMR0Ex(NIL_RTR0PTR, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
52}
53
54
55/**
56 * Copys the SG segments into the specified fram.
57 *
58 * @param pvFrame The frame buffer.
59 * @param cSegs The number of segments.
60 * @param paSegs The segments.
61 */
62static void vboxnetIntIfCopySG(void *pvFrame, size_t cSegs, PCINTNETSEG paSegs)
63{
64 uint8_t *pbDst = (uint8_t *)pvFrame;
65 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
66 {
67 memcpy(pbDst, paSegs[iSeg].pv, paSegs[iSeg].cb);
68 pbDst += paSegs[iSeg].cb;
69 }
70}
71
72
73/**
74 * Writes a frame packet to the buffer.
75 *
76 * @returns VBox status code.
77 * @param pBuf The buffer.
78 * @param pRingBuf The ring buffer to read from.
79 * @param cSegs The number of segments.
80 * @param paSegs The segments.
81 * @remark This is the same as INTNETRingWriteFrame and
82 * drvIntNetRingWriteFrame.
83 */
84int VBoxNetIntIfRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, size_t cSegs, PCINTNETSEG paSegs)
85{
86 /*
87 * Validate input.
88 */
89 Assert(pBuf);
90 Assert(pRingBuf);
91 uint32_t offWrite = pRingBuf->offWrite;
92 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
93 uint32_t offRead = pRingBuf->offRead;
94 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
95 AssertPtr(paSegs);
96 Assert(cSegs > 0);
97
98 /* Calc frame size. */
99 uint32_t cbFrame = 0;
100 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
101 cbFrame += paSegs[iSeg].cb;
102
103 Assert(cbFrame >= sizeof(RTMAC) * 2);
104
105
106 const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
107 if (offRead <= offWrite)
108 {
109 /*
110 * Try fit it all before the end of the buffer.
111 */
112 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
113 {
114 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
115 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
116 pHdr->cbFrame = cbFrame;
117 pHdr->offFrame = sizeof(INTNETHDR);
118
119 vboxnetIntIfCopySG(pHdr + 1, cSegs, paSegs);
120
121 offWrite += cb + sizeof(INTNETHDR);
122 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
123 if (offWrite >= pRingBuf->offEnd)
124 offWrite = pRingBuf->offStart;
125 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
126 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
127 return VINF_SUCCESS;
128 }
129
130 /*
131 * Try fit the frame at the start of the buffer.
132 * (The header fits before the end of the buffer because of alignment.)
133 */
134 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
135 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
136 {
137 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
138 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
139 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
140 pHdr->cbFrame = cbFrame;
141 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
142
143 vboxnetIntIfCopySG(pvFrameOut, cSegs, paSegs);
144
145 offWrite = pRingBuf->offStart + cb;
146 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
147 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
148 return VINF_SUCCESS;
149 }
150 }
151 /*
152 * The reader is ahead of the writer, try fit it into that space.
153 */
154 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
155 {
156 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
157 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
158 pHdr->cbFrame = cbFrame;
159 pHdr->offFrame = sizeof(INTNETHDR);
160
161 vboxnetIntIfCopySG(pHdr + 1, cSegs, paSegs);
162
163 offWrite += cb + sizeof(INTNETHDR);
164 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
165 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
166 return VINF_SUCCESS;
167 }
168
169 /* (it didn't fit) */
170 /** @todo stats */
171 return VERR_BUFFER_OVERFLOW;
172}
173
174
175/**
176 * Sends a frame
177 *
178 * @returns VBox status code.
179 * @param pSession The support driver session.
180 * @param hIf The interface handle.
181 * @param pBuf The interface buffer.
182 * @param cSegs The number of segments.
183 * @param paSegs The segments.
184 * @param fFlush Whether to flush the write.
185 */
186int VBoxNetIntIfSend(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf,
187 size_t cSegs, PCINTNETSEG paSegs, bool fFlush)
188{
189 int rc = VBoxNetIntIfRingWriteFrame(pBuf, &pBuf->Send, cSegs, paSegs);
190 if (rc == VERR_BUFFER_OVERFLOW)
191 {
192 VBoxNetIntIfFlush(pSession, hIf);
193 rc = VBoxNetIntIfRingWriteFrame(pBuf, &pBuf->Send, cSegs, paSegs);
194 }
195 if (RT_SUCCESS(rc) && fFlush)
196 rc = VBoxNetIntIfFlush(pSession, hIf);
197 return rc;
198}
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