VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp@ 10923

Last change on this file since 10923 was 10923, checked in by vboxsync, 17 years ago

intnet: MAC sharing under construction...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 113.6 KB
Line 
1/* $Id: SrvIntNetR0.cpp 10923 2008-07-29 00:22:11Z vboxsync $ */
2/** @file
3 * Internal networking - The ring 0 service.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_SRV_INTNET
27#include <VBox/intnet.h>
28#include <VBox/sup.h>
29#include <VBox/pdm.h>
30#include <VBox/log.h>
31#include <iprt/asm.h>
32#include <iprt/alloc.h>
33#include <iprt/semaphore.h>
34#include <iprt/spinlock.h>
35#include <iprt/thread.h>
36#include <iprt/assert.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#include <iprt/handletable.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef enum INTNETADDRTYPE
46{
47 /** The invalid 0 entry. */
48 kIntNetAddrType_Invalid = 0,
49 /** IP version 4. */
50 kIntNetAddrType_IPv4,
51 /** IP version 6. */
52 kIntNetAddrType_IPv6,
53 /** IPX. */
54 kIntNetAddrType_IPX,
55 /** The end of the valid values. */
56 kIntNetAddrType_End,
57 /** The usual 32-bit hack. */
58 kIntNetAddrType_32BitHack = 0x7fffffff
59} INTNETADDRTYPE;
60/** Pointer to a network layer address type. */
61typedef INTNETADDRTYPE *PINTNETADDRTYPE;
62
63/**
64 * IPv4 address.
65 */
66typedef RTUINT32U INTNETADDRIPV4;
67/** Pointer to a IPv4 address. */
68typedef INTNETADDRIPV4 *PINTNETADDRIPV4;
69/** Pointer to a const IPv4 address. */
70typedef INTNETADDRIPV4 const *PCINTNETADDRIPV4;
71
72/**
73 * IPv6 address.
74 */
75typedef RTUINT128U INTNETADDRIPV6;
76/** Pointer to a IPv4 address. */
77typedef INTNETADDRIPV6 *PINTNETADDRIPV6;
78/** Pointer to a const IPv4 address. */
79typedef INTNETADDRIPV6 const *PCINTNETADDRIPV6;
80
81/**
82 * IPX address.
83 */
84typedef struct INTNETADDRIPX
85{
86 /** The network ID. */
87 uint32_t Network;
88 /** The node ID. (Defaults to the MAC address apparently.) */
89 PDMMAC Node;
90} INTNETADDRIPX;
91/** Pointer to an IPX address. */
92typedef INTNETADDRIPX *PINTNETADDRIPX;
93/** Pointer to a const IPX address. */
94typedef INTNETADDRIPX const *PCINTNETADDRIPX;
95
96/**
97 * Address union.
98 */
99typedef union INTNETADDRU
100{
101 /** 64-bit view. */
102 uint64_t au64[2];
103 /** 32-bit view. */
104 uint32_t au32[4];
105 /** 16-bit view. */
106 uint16_t au16[8];
107 /** 8-bit view. */
108 uint8_t au8[16];
109 /** IPv4 view. */
110 INTNETADDRIPV4 IPv4;
111 /** IPv6 view. */
112 INTNETADDRIPV6 IPv6;
113 /** IPX view. */
114 INTNETADDRIPX Ipx;
115} INTNETADDRU;
116/** Pointer to an address union. */
117typedef INTNETADDRU *PINTNETADDRU;
118/** Pointer to a const address union. */
119typedef INTNETADDRU const *PCINTNETADDRU;
120
121/**
122 * Address and type.
123 */
124typedef struct INTNETADDR
125{
126 /** The address type. */
127 INTNETADDRTYPE enmType;
128 /** The address. */
129 INTNETADDRU Addr;
130} INTNETADDR;
131/** Pointer to an address. */
132typedef INTNETADDR *PINTNETADDR;
133/** Pointer to a const address. */
134typedef INTNETADDR const *PCINTNETADDR;
135
136
137/**
138 * Address cache for a specific network layer.
139 */
140typedef struct INTNETADDRCACHE
141{
142 /** Pointer to the table of addresses. */
143 uint8_t *pbEntries;
144 /** The number of valid address entries. */
145 uint8_t cEntries;
146 /** The number of allocated address entries. */
147 uint8_t cEntriesAlloc;
148 /** The address size. */
149 uint8_t cbAddress;
150 /** The size of an entry. */
151 uint8_t cbEntry;
152} INTNETADDRCACHE;
153/** Pointer to an address cache. */
154typedef INTNETADDRCACHE *PINTNETADDRCACHE;
155/** Pointer to a const address cache. */
156typedef INTNETADDRCACHE const *PCINTNETADDRCACHE;
157
158
159/**
160 * A network interface.
161 *
162 * Unless explicitly stated, all members are protect by the network semaphore.
163 */
164typedef struct INTNETIF
165{
166 /** Pointer to the next interface.
167 * This is protected by the INTNET::FastMutex. */
168 struct INTNETIF *pNext;
169 /** The current MAC address for the interface. */
170 PDMMAC Mac;
171 /** Set if the INTNET::Mac member is valid. */
172 bool fMacSet;
173 /** Set if the interface is in promiscuous mode.
174 * In promiscuous mode the interface will receive all packages except the one it's sending. */
175 bool fPromiscuous;
176 /** Whether the interface is active or not. */
177 bool fActive;
178 /** Whether someone is currently in the destructor. */
179 bool volatile fDestroying;
180 /** Number of yields done to try make the interface read pending data.
181 * We will stop yeilding when this reaches a threshold assuming that the VM is paused or
182 * that it simply isn't worth all the delay. It is cleared when a successful send has been done.
183 */
184 uint32_t cYields;
185 /** Pointer to the current exchange buffer (ring-0). */
186 PINTNETBUF pIntBuf;
187 /** Pointer to ring-3 mapping of the current exchange buffer. */
188 R3PTRTYPE(PINTNETBUF) pIntBufR3;
189 /** Pointer to the default exchange buffer for the interface. */
190 PINTNETBUF pIntBufDefault;
191 /** Pointer to ring-3 mapping of the default exchange buffer. */
192 R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3;
193 /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
194 RTSEMEVENT volatile Event;
195 /** Number of threads sleeping on the Event semaphore. */
196 uint32_t cSleepers;
197 /** The interface handle.
198 * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
199 * should return with the appropriate error condition. */
200 INTNETIFHANDLE volatile hIf;
201 /** Pointer to the network this interface is connected to.
202 * This is protected by the INTNET::FastMutex. */
203 struct INTNETNETWORK *pNetwork;
204 /** The session this interface is associated with. */
205 PSUPDRVSESSION pSession;
206 /** The SUPR0 object id. */
207 void *pvObj;
208 /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */
209 INTNETADDRCACHE aAddrCache[kIntNetAddrType_End];
210} INTNETIF;
211/** Pointer to an internal network interface. */
212typedef INTNETIF *PINTNETIF;
213
214
215/**
216 * A trunk interface.
217 */
218typedef struct INTNETTRUNKIF
219{
220 /** The port interface we present to the component. */
221 INTNETTRUNKSWPORT SwitchPort;
222 /** The port interface we get from the component. */
223 PINTNETTRUNKIFPORT pIfPort;
224 /** The trunk mutex that serializes all calls <b>to</b> the component. */
225 RTSEMFASTMUTEX FastMutex;
226 /** Pointer to the network we're connect to.
227 * This may be NULL if we're orphaned? */
228 struct INTNETNETWORK *pNetwork;
229 /** Whether to supply physical addresses with the outbound SGs. */
230 bool volatile fPhysSG;
231 /** Set if the 'wire' is in promiscuous mode.
232 * The state of the 'host' is queried each time. */
233 bool fPromiscuousWire;
234} INTNETTRUNKIF;
235/** Pointer to a trunk interface. */
236typedef INTNETTRUNKIF *PINTNETTRUNKIF;
237
238/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
239#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
240
241
242/**
243 * Internal representation of a network.
244 */
245typedef struct INTNETNETWORK
246{
247 /** The Next network in the chain.
248 * This is protected by the INTNET::FastMutex. */
249 struct INTNETNETWORK *pNext;
250 /** List of interfaces connected to the network.
251 * This is protected by the INTNET::FastMutex. */
252 PINTNETIF pIFs;
253 /** Pointer to the trunk interface.
254 * Can be NULL if there is no trunk connection. */
255 PINTNETTRUNKIF pTrunkIF;
256 /** The network mutex.
257 * It protects everything dealing with this network. */
258 RTSEMFASTMUTEX FastMutex;
259 /** Pointer to the instance data. */
260 struct INTNET *pIntNet;
261 /** The SUPR0 object id. */
262 void *pvObj;
263 /** Network creation flags (INTNET_OPEN_FLAGS_*). */
264 uint32_t fFlags;
265 /** The number of active interfaces (excluding the trunk). */
266 uint32_t cActiveIFs;
267 /** The length of the network name. */
268 uint8_t cchName;
269 /** The network name. */
270 char szName[INTNET_MAX_NETWORK_NAME];
271 /** The trunk type. */
272 INTNETTRUNKTYPE enmTrunkType;
273 /** The trunk name. */
274 char szTrunk[INTNET_MAX_TRUNK_NAME];
275} INTNETNETWORK;
276/** Pointer to an internal network. */
277typedef INTNETNETWORK *PINTNETNETWORK;
278
279
280/**
281 * Internal networking instance.
282 */
283typedef struct INTNET
284{
285 /** Mutex protecting the network creation, opening and destruction.
286 * (This means all operations affecting the pNetworks list.) */
287 RTSEMFASTMUTEX FastMutex;
288 /** List of networks. Protected by INTNET::Spinlock. */
289 PINTNETNETWORK volatile pNetworks;
290 /** Handle table for the interfaces. */
291 RTHANDLETABLE hHtIfs;
292} INTNET;
293
294
295/**
296 * Ethernet header.
297 */
298#pragma pack(1)
299typedef struct INTNETETHERHDR
300{
301 PDMMAC MacDst;
302 PDMMAC MacSrc;
303 uint16_t EtherType;
304} INTNETETHERHDR;
305#pragma pack()
306/** Pointer to an ethernet header. */
307typedef INTNETETHERHDR *PINTNETETHERHDR;
308/** Pointer to a const ethernet header. */
309typedef INTNETETHERHDR const *PCINTNETETHERHDR;
310
311/** @name EtherType
312 * @{ */
313#define INTNET_ETHERTYPE_IPV4 UINT16_C(0x0800)
314#define INTNET_ETHERTYPE_ARP UINT16_C(0x0806)
315#define INTNET_ETHERTYPE_IPV6 UINT16_C(0x86dd)
316/** @} */
317
318
319#pragma pack(1)
320typedef struct INTNETIPV4
321{
322#ifdef RT_BIG_ENDIAN
323 unsigned int ip_v : 4;
324 unsigned int ip_hl : 4;
325 unsigned int ip_tos : 8;
326 unsigned int ip_len : 16;
327#else
328 unsigned int ip_hl : 4;
329 unsigned int ip_v : 4;
330 unsigned int ip_tos : 8;
331 unsigned int ip_len : 16;
332#endif
333 uint16_t ip_id;
334 uint16_t ip_off;
335 uint8_t ip_ttl;
336 uint8_t ip_p;
337 uint16_t ip_sum;
338 uint32_t ip_src;
339 uint32_t ip_dst;
340 /* more */
341 uint32_t ip_options[1];
342} INTNETIPV4;
343typedef INTNETIPV4 *PINTNETIPV4;
344typedef INTNETIPV4 const *PCINTNETIPV4;
345
346
347typedef struct INTNETUDPV4
348{
349 uint16_t uh_sport;
350 uint16_t uh_dport;
351 uint16_t uh_ulen;
352 uint16_t uh_sum;
353} INTNETUDPV4;
354typedef INTNETUDPV4 *PINTNETUDPV4;
355typedef INTNETUDPV4 const *PCINTNETUDPV4;
356
357
358typedef struct INTNETDHCP
359{
360 uint8_t Op;
361 uint8_t HType;
362 uint8_t HLen;
363 uint8_t Hops;
364 uint32_t XID;
365 uint16_t Secs;
366 uint16_t Flags;
367 uint32_t CIAddr;
368 uint32_t YIAddr;
369 uint32_t SIAddr;
370 uint32_t GIAddr;
371 uint8_t CHAddr[16];
372 uint8_t SName[64];
373 uint8_t File[128];
374 uint8_t abMagic[4];
375 uint8_t DhcpOpt;
376 uint8_t DhcpLen; /* 1 */
377 uint8_t DhcpReq;
378 uint8_t abOptions[57];
379} INTNETDHCP;
380typedef INTNETDHCP *PINTNETDHCP;
381typedef INTNETDHCP const *PCINTNETDHCP;
382
383#pragma pack(0)
384
385/** IPv4: UDP */
386#define INTNETIPV4_PROT_UDP 7
387
388
389/** ARP hardware type - ethernet. */
390#define INTNET_ARP_ETHER UINT16_C(1)
391
392/** @name ARP operations
393 * @{ */
394#define INTNET_ARPOP_REQUEST UINT16_C(1) /**< Request hardward address given a protocol address (ARP). */
395#define INTNET_ARPOP_REPLY UINT16_C(2)
396#define INTNET_ARPOP_REVREQUEST UINT16_C(3) /**< Request protocol address given a hardware address (RARP). */
397#define INTNET_ARPOP_REVREPLY UINT16_C(4)
398#define INTNET_ARPOP_INVREQUEST UINT16_C(8) /**< Inverse ARP. */
399#define INTNET_ARPOP_INVREPLY UINT16_C(9)
400#define INTNET_ARPOP_IS_REQUEST(Op) ((Op) & 1)
401#define INTNET_ARPOP_IS_REPLY(Op) (!INTNET_ARPOP_IS_REQUEST(Op))
402/** @} */
403
404#pragma pack(1)
405/**
406 * Ethernet ARP header.
407 */
408typedef struct INTNETARPHDR
409{
410 /** The hardware type. */
411 uint16_t ar_htype;
412 /** The protocol type (ethertype). */
413 uint16_t ar_ptype;
414 /** The hardware address length. */
415 uint8_t ar_hlen;
416 /** The protocol address length. */
417 uint8_t ar_plen;
418 /** The operation. */
419 uint16_t ar_oper;
420} INTNETARPHDR;
421#pragma pack(0)
422/** Pointer to an ethernet ARP header. */
423typedef INTNETARPHDR *PINTNETARPHDR;
424/** Pointer to a const ethernet ARP header. */
425typedef INTNETARPHDR const *PCINTNETARPHDR;
426
427
428#pragma pack(1)
429/**
430 * Ethernet IPv4 + 6-byte MAC ARP request packet.
431 */
432typedef struct INTNETARPIPV4
433{
434 INTNETARPHDR Hdr;
435 /** The sender hardware address. */
436 PDMMAC ar_sha;
437 /** The sender protocol address. */
438 INTNETADDRIPV4 ar_spa;
439 /** The target hardware address. */
440 PDMMAC ar_tha;
441 /** The arget protocol address. */
442 INTNETADDRIPV4 ar_tpa;
443} INTNETARPIPV4;
444#pragma pack(0)
445/** Pointer to an ethernet IPv4+MAC ARP request packet. */
446typedef INTNETARPIPV4 *PINTNETARPIPV4;
447/** Pointer to a const ethernet IPv4+MAC ARP request packet. */
448typedef INTNETARPIPV4 const *PCINTNETARPIPV4;
449
450
451#pragma pack(1)
452/**
453 * Ethernet IPv6 + 6-byte MAC ARP request packet.
454 */
455typedef struct INTNETARPIPV6
456{
457 INTNETARPHDR Hdr;
458 /** The sender hardware address. */
459 PDMMAC ar_sha;
460 /** The sender protocol address. */
461 INTNETADDRIPV6 ar_spa;
462 /** The target hardware address. */
463 PDMMAC ar_tha;
464 /** The arget protocol address. */
465 INTNETADDRIPV6 ar_tpa;
466} INTNETARPIPV6;
467#pragma pack(0)
468/** Pointer to an ethernet IPv6+MAC ARP request packet. */
469typedef INTNETARPIPV6 *PINTNETARPIPV6;
470/** Pointer to a const ethernet IPv6+MAC ARP request packet. */
471typedef INTNETARPIPV6 const *PCINTNETARPIPV6;
472
473
474/*******************************************************************************
475* Internal Functions *
476*******************************************************************************/
477static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis);
478static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis);
479static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis);
480static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis);
481
482
483
484/**
485 * Retain an interface.
486 *
487 * @returns VBox status code, can assume success in most situations.
488 * @param pIf The interface instance.
489 * @param pSession The current session.
490 */
491DECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession)
492{
493 int rc = SUPR0ObjAddRef(pIf->pvObj, pSession);
494 AssertRCReturn(rc, rc);
495 return VINF_SUCCESS;
496}
497
498
499/**
500 * Release an interface previously retained by intnetR0IfRetain or
501 * by handle lookup/freeing.
502 *
503 * @returns VBox status code, can assume success in most situations.
504 * @param pIf The interface instance.
505 * @param pSession The current session.
506 */
507DECLINLINE(void) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession)
508{
509 int rc = SUPR0ObjRelease(pIf->pvObj, pSession);
510 AssertRC(rc);
511}
512
513
514/**
515 * RTHandleCreateEx callback that retains an object in the
516 * handle table before returning it.
517 *
518 * (Avoids racing the freeing of the handle.)
519 *
520 * @returns VBox status code.
521 * @param hHandleTable The handle table (ignored).
522 * @param pvObj The object (INTNETIF).
523 * @param pvCtx The context (SUPDRVSESSION).
524 * @param pvUser The user context (ignored).
525 */
526static DECLCALLBACK(int) intnetR0IfRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
527{
528 NOREF(pvUser);
529 NOREF(hHandleTable);
530 PINTNETIF pIf = (PINTNETIF)pvObj;
531 if (pIf->hIf != INTNET_HANDLE_INVALID) /* Don't try retain it if called from intnetR0IfDestruct. */
532 return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx);
533 return VINF_SUCCESS;
534}
535
536
537/**
538 * Gets the address size of a network layer type.
539 *
540 * @returns size in bytes.
541 * @param enmType The type.
542 */
543DECLINLINE(uint8_t) intnetR0AddrSize(INTNETADDRTYPE enmType)
544{
545 switch (enmType)
546 {
547 case kIntNetAddrType_IPv4: return 4;
548 case kIntNetAddrType_IPv6: return 16;
549 case kIntNetAddrType_IPX: return 4 + 6;
550 default: AssertFailedReturn(0);
551 }
552}
553
554
555/**
556 * Compares two address to see if they are equal, assuming naturally align structures.
557 *
558 * @returns true if equal, false if not.
559 * @param pAddr1 The first address.
560 * @param pAddr2 The second address.
561 * @param cbAddr The address size.
562 */
563DECLINLINE(bool) intnetR0AddrUIsEqualEx(PCINTNETADDRU pAddr1, PCINTNETADDRU pAddr2, uint8_t const cbAddr)
564{
565 switch (cbAddr)
566 {
567 case 4: /* IPv4 */
568 return pAddr1->au32[0] == pAddr2->au32[0];
569 case 16: /* IPv6 */
570 return pAddr1->au64[0] == pAddr2->au64[0]
571 && pAddr1->au64[1] == pAddr2->au64[1];
572 case 10: /* IPX */
573 return pAddr1->au64[0] == pAddr2->au64[0]
574 && pAddr1->au16[4] == pAddr2->au16[4];
575 default:
576 AssertFailedReturn(false);
577 }
578}
579
580
581/**
582 * Worker for intnetR0IfAddrCacheLookup that performs the lookup
583 * in the remaining cache entries after the caller has check the
584 * most likely ones.
585 *
586 * @returns -1 if not found, the index of the cache entry if found.
587 * @param pCache The cache.
588 * @param pAddr The address.
589 * @param cbAddr The address size (optimization).
590 */
591static int intnetR0IfAddrCacheLookupSlow(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
592{
593 unsigned i = pCache->cEntries - 2;
594 uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
595 while (i >= 1)
596 {
597 if (intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr))
598 return i;
599 pbEntry -= pCache->cbEntry;
600 i--;
601 }
602
603 return -1;
604}
605
606/**
607 * Lookup an address in a cache without any expectations.
608 *
609 * @returns -1 if not found, the index of the cache entry if found.
610 * @param pCache The cache.
611 * @param pAddr The address.
612 * @param cbAddr The address size (optimization).
613 */
614DECLINLINE(int) intnetR0IfAddrCacheLookup(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
615{
616 Assert(pCache->cbAddress == cbAddr);
617
618 /*
619 * The optimized case is when there is one cache entry and
620 * it doesn't match.
621 */
622 unsigned i = pCache->cEntries;
623 if ( i > 0
624 && intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr))
625 return 0;
626 if (i <= 1)
627 return -1;
628
629 /*
630 * Check the last entry.
631 */
632 i--;
633 if (intnetR0AddrUIsEqualEx((PCINTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))
634 return i;
635 if (i <= 1)
636 return -1;
637
638 return intnetR0IfAddrCacheLookupSlow(pCache, pAddr, cbAddr);
639}
640
641/** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */
642DECLINLINE(int) intnetR0IfAddrCacheLookupLikely(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
643{
644 /** @todo implement this. */
645 return intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
646}
647
648
649/**
650 * Worker for intnetR0IfAddrCacheLookupUnlikely that performs
651 * the lookup in the remaining cache entries after the caller
652 * has check the most likely ones.
653 *
654 * The routine is expecting not to find the address.
655 *
656 * @returns -1 if not found, the index of the cache entry if found.
657 * @param pCache The cache.
658 * @param pAddr The address.
659 * @param cbAddr The address size (optimization).
660 */
661static int intnetR0IfAddrCacheInCacheUnlikelySlow(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
662{
663 /*
664 * Perform a full table lookup.
665 */
666 unsigned i = pCache->cEntries - 2;
667 uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
668 while (i >= 1)
669 {
670 if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr)))
671 return i;
672 pbEntry -= pCache->cbEntry;
673 i--;
674 }
675
676 return -1;
677}
678
679
680/**
681 * Lookup an address in a cache expecting not to find it.
682 *
683 * @returns -1 if not found, the index of the cache entry if found.
684 * @param pCache The cache.
685 * @param pAddr The address.
686 * @param cbAddr The address size (optimization).
687 */
688DECLINLINE(int) intnetR0IfAddrCacheLookupUnlikely(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
689{
690 Assert(pCache->cbAddress == cbAddr);
691
692 /*
693 * The optimized case is when there is one cache entry and
694 * it doesn't match.
695 */
696 unsigned i = pCache->cEntries;
697 if (RT_UNLIKELY( i > 0
698 && intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
699 return 0;
700 if (RT_LIKELY(i <= 1))
701 return -1;
702
703 /*
704 * Then check the last entry and return if there are just two cache entries.
705 */
706 i--;
707 if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr)))
708 return i;
709 if (i <= 1)
710 return -1;
711
712 return intnetR0IfAddrCacheInCacheUnlikelySlow(pCache, pAddr, cbAddr);
713}
714
715
716/**
717 * Deletes a specific cache entry.
718 *
719 * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf.
720 *
721 * @param pIf The interface (for logging).
722 * @param pCache The cache.
723 * @param iEntry The entry to delete.
724 */
725static void intnetR0IfAddrCacheDeleteIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, int iEntry)
726{
727 Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 type=%d #%d %.*Rhxs\n", pIf->hIf,
728 (int)(intptr_t)(pCache - &pIf->aAddrCache[0]), iEntry, pCache->cbAddress, pCache->pbEntries + iEntry * pCache->cbEntry));
729 Assert(iEntry < pCache->cEntries);
730 pCache->cEntries--;
731 if (iEntry < pCache->cEntries)
732 memmove(pCache->pbEntries + iEntry * pCache->cbEntry,
733 pCache->pbEntries + (iEntry + 1) * pCache->cbEntry,
734 (pCache->cEntries - iEntry) * pCache->cbEntry);
735}
736
737
738/**
739 * Deletes an address from the cache, assuming it isn't actually in the cache.
740 *
741 * @param pIf The interface (for logging).
742 * @param pCache The cache.
743 * @param pAddr The address.
744 * @param cbAddr The address size (optimization).
745 */
746DECLINLINE(void) intnetR0IfAddrCacheDelete(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
747{
748 int i = intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
749 if (RT_UNLIKELY(i >= 0))
750 intnetR0IfAddrCacheDeleteIt(pIf, pCache, i);
751}
752
753
754/**
755 * Deletes the address from all the interface caches.
756 *
757 * This is used to remove stale entries that has been reassigned to
758 * other machines on the network.
759 *
760 * @param pNetwork The network.
761 * @param pAddr The address.
762 * @param enmType The address type.
763 * @param cbAddr The address size (optimization).
764 */
765DECLINLINE(void) intnetR0NetworkAddrCacheDelete(PINTNETNETWORK pNetwork, PCINTNETADDRU pAddr,
766 INTNETADDRTYPE const enmType, uint8_t const cbAddr)
767{
768 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
769 {
770 int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
771 if (RT_UNLIKELY(i >= 0))
772 intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i);
773 }
774}
775
776
777/**
778 * Deletes the address from all the interface caches except the specified one.
779 *
780 * This is used to remove stale entries that has been reassigned to
781 * other machines on the network.
782 *
783 * @param pNetwork The network.
784 * @param pAddr The address.
785 * @param enmType The address type.
786 * @param cbAddr The address size (optimization).
787 */
788DECLINLINE(void) intnetR0NetworkAddrCacheDeleteMinusIf(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCINTNETADDRU pAddr,
789 INTNETADDRTYPE const enmType, uint8_t const cbAddr)
790{
791 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
792 if (pIf != pIfSender)
793 {
794 int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
795 if (RT_UNLIKELY(i >= 0))
796 intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i);
797 }
798}
799
800
801/**
802 * Adds an address to the cache, the caller is responsible for making sure it'
803 * s not already in the cache.
804 *
805 * @param pIf The interface (for logging).
806 * @param pCache The address cache.
807 * @param pAddr The address.
808 */
809static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr)
810{
811 if (!pCache->cEntriesAlloc)
812 {
813 /* Allocate the first array */
814 pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 16);
815 if (!pCache->pbEntries)
816 return;
817 }
818 else
819 {
820 bool fReplace = true;
821 if (pCache->cEntriesAlloc < 64)
822 {
823 uint8_t cEntriesAlloc = pCache->cEntriesAlloc + 16;
824 void *pvNew = RTMemRealloc(pCache->pbEntries, pCache->cbEntry * cEntriesAlloc);
825 if (pvNew)
826 {
827 pCache->pbEntries = (uint8_t *)pvNew;
828 pCache->cEntriesAlloc = cEntriesAlloc;
829 fReplace = false;
830 }
831 }
832 if (fReplace)
833 {
834 /* simple FIFO, might consider usage/ageing here? */
835 Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
836 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
837 memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
838 pCache->cEntries--;
839 }
840 }
841
842 /*
843 * Add the new entry to the end of the array.
844 */
845 uint8_t *pbEntry = pCache->pbEntries + pCache->cEntries * pCache->cbEntry;
846 memcpy(pbEntry, pAddr, pCache->cbAddress);
847 memset(pbEntry + pCache->cbAddress, '\0', pCache->cbEntry - pCache->cbAddress);
848 Log(("intnetR0IfAddrCacheAddIt: type=%d added #%d %.*Rhxs\n",
849 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cEntries, pCache->cbAddress, pAddr));
850 pCache->cEntries++;
851 Assert(pCache->cEntries <= pCache->cEntriesAlloc);
852}
853
854
855/**
856 * A intnetR0IfAddrCacheAdd worker that performs the rest of the lookup.
857 *
858 * @param pIf The interface (for logging).
859 * @param pCache The address cache.
860 * @param pAddr The address.
861 * @param cbAddr The size of the address (optimization).
862 */
863static void intnetR0IfAddrCacheAddSlow(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
864{
865 /*
866 * Check all but the first and last entries, the caller
867 * has already checked those.
868 */
869 unsigned cLeft = pCache->cEntries;
870 uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry;
871 while (--cLeft > 1)
872 {
873 if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr)))
874 {
875 /** @todo usage/ageing? */
876 return;
877 }
878 pbEntry += pCache->cbEntry;
879 cLeft--;
880 }
881
882 /*
883 * Not found, add it.
884 */
885 intnetR0IfAddrCacheAddIt(pIf, pCache, pAddr);
886}
887
888
889/**
890 * Adds an address to the cache if it's not already there.
891 *
892 * @param pIf The interface (for logging).
893 * @param pCache The address cache.
894 * @param pAddr The address.
895 * @param cbAddr The size of the address (optimization).
896 */
897DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
898{
899 Assert(pCache->cbAddress == cbAddr);
900
901 /*
902 * The optimized case is when the address the first cache entry.
903 */
904 unsigned i = pCache->cEntries;
905 if (RT_LIKELY( i > 0
906 && intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
907 {
908 /** @todo usage/ageing? */
909 return;
910 }
911 if (i <= 1)
912 return;
913
914 /*
915 * And the case where it's the last entry.
916 */
917 i--;
918 if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
919 {
920 /** @todo usage/ageing? */
921 return;
922 }
923 if (i <= 1)
924 return;
925
926 intnetR0IfAddrCacheAddSlow(pIf, pCache, pAddr, cbAddr);
927}
928
929
930/**
931 * Deals with an IPv4 packet.
932 *
933 * This will fish out the source IP address and add it to the cache.
934 * Then it will look for DHCPRELEASE requests (?) and anything else
935 * that we migh find useful later.
936 *
937 * @param pIf The interface that's sending the frame.
938 * @param pHdr Pointer to the IPv4 header in the frame.
939 * @param cbPacket The size of the packet, or more correctly the
940 * size of the frame without the ethernet header.
941 */
942static void intnetR0IfSniffIPv4SourceAddr(PINTNETIF pIf, PCINTNETIPV4 pHdr, uint32_t cbPacket)
943{
944 /*
945 * Check the header size.
946 */
947 if (cbPacket < RT_UOFFSETOF(INTNETIPV4, ip_options)) /** @todo check minimum size requirements here. */
948 return;
949 uint32_t cbHdr = (uint32_t)pHdr->ip_hl * 4;
950 if ( cbHdr < RT_UOFFSETOF(INTNETIPV4, ip_options)
951 || cbPacket < cbHdr)
952 return;
953
954 /*
955 * Ignore 255.255.255.255 (broadcast), 0.0.0.0 (null) and already cached addresses.
956 */
957 INTNETADDRU Addr;
958 Addr.au32[0] = pHdr->ip_src;
959 if (Addr.au32[0] == UINT32_C(0xffffffff))
960 return;
961
962 int i = -1;
963 if ( Addr.au32[0] == 0
964 || (i = intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pHdr->ip_src))) >= 0)
965 {
966#if 0 /** @todo quick DHCP check? */
967 if (pHdr->ip_p != INTNETIPV4_PROT_UDP)
968 return;
969#endif
970 return;
971 }
972
973 /*
974 * Check the header checksum.
975 */
976 /** @todo IP checksumming */
977
978 /*
979 * Add the source address.
980 */
981 if (i < 0)
982 intnetR0IfAddrCacheAddIt(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr);
983
984 /*
985 * Check for DHCP (properly this time).
986 */
987 /** @todo DHCPRELEASE request? */
988}
989
990
991
992/**
993 * Sniff up source addresses from an ARP request or reply.
994 *
995 * @param pIf The interface that's sending the frame.
996 * @param pHdr The ARP header.
997 * @param cbPacket The size of the packet (migth be larger than the ARP
998 * request 'cause of min ethernet frame size).
999 */
1000static void intnetR0IfSniffArpSourceAddr(PINTNETIF pIf, PCINTNETARPHDR pHdr, uint32_t cbPacket)
1001{
1002 /*
1003 * Ignore malformed packets and packets which doesn't interrest us.
1004 */
1005 if (RT_UNLIKELY( cbPacket <= sizeof(*pHdr)
1006 || pHdr->ar_hlen != sizeof(PDMMAC)
1007 || pHdr->ar_htype != RT_H2BE_U16(INTNET_ARP_ETHER)
1008 || ( pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REQUEST)
1009 && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REPLY)
1010 && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REVREQUEST)
1011 && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REVREPLY)
1012 /** @todo Read up on inverse ARP. */
1013 )
1014 )
1015 )
1016 return;
1017
1018 /*
1019 * Deal with the protocols.
1020 */
1021 INTNETADDRU Addr;
1022 if (pHdr->ar_ptype == RT_H2BE_U16(INTNET_ETHERTYPE_IPV4))
1023 {
1024 /*
1025 * IPv4.
1026 */
1027 PCINTNETARPIPV4 pReq = (PCINTNETARPIPV4)pHdr;
1028 if (RT_UNLIKELY( pHdr->ar_plen == sizeof(pReq->ar_spa)
1029 || cbPacket < sizeof(*pReq)
1030 || pReq->ar_spa.u == 0 /** @todo add an inline function for checking that an IP address is worth caching. */
1031 || pReq->ar_spa.u == UINT32_C(0xffffffff)))
1032 return;
1033
1034 if (INTNET_ARPOP_IS_REPLY(RT_BE2H_U16(pHdr->ar_oper)))
1035 {
1036 Addr.IPv4 = pReq->ar_tpa;
1037 intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pReq->ar_tpa));
1038 }
1039 Addr.IPv4 = pReq->ar_spa;
1040 intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pReq->ar_spa));
1041 }
1042 else if (pHdr->ar_ptype == RT_H2BE_U16(INTNET_ETHERTYPE_IPV6))
1043 {
1044 /*
1045 * IPv6.
1046 */
1047 PCINTNETARPIPV6 pReq = (PCINTNETARPIPV6)pHdr;
1048 if (RT_UNLIKELY( pHdr->ar_plen == sizeof(pReq->ar_spa)
1049 || cbPacket < sizeof(*pReq)
1050 /** @todo IPv6 || pReq->ar_spa.au32[0] == 0 or something
1051 || pReq->ar_spa.au32[0] == UINT32_C(0xffffffff)*/))
1052 return;
1053
1054 if (INTNET_ARPOP_IS_REPLY(RT_BE2H_U16(pHdr->ar_oper)))
1055 {
1056 Addr.IPv6 = pReq->ar_tpa;
1057 intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(pReq->ar_tpa));
1058 }
1059 Addr.IPv6 = pReq->ar_spa;
1060 intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(pReq->ar_spa));
1061 }
1062 else
1063 Log(("intnetR0IfSniffArpSourceAddr: unknown ar_ptype=%#x\n", RT_BE2H_U16(pHdr->ar_ptype)));
1064}
1065
1066
1067
1068/**
1069 * Checks packets send by a normal interface for new network
1070 * layer addresses.
1071 *
1072 * @param pIf The interface that's sending the frame.
1073 * @param pbFrame The frame.
1074 * @param cbFrame The size of the frame.
1075 */
1076static void intnetR0IfSniffSourceAddr(PINTNETIF pIf, uint8_t const *pbFrame, uint32_t cbFrame)
1077{
1078 /*
1079 * Fish out the ethertype and look for stuff we can handle.
1080 */
1081 if (cbFrame <= sizeof(INTNETETHERHDR))
1082 return;
1083 cbFrame -= sizeof(INTNETETHERHDR);
1084
1085 uint16_t EtherType = ((PCINTNETETHERHDR)pbFrame)->EtherType;
1086 if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_IPV4))
1087 intnetR0IfSniffIPv4SourceAddr(pIf, (PCINTNETIPV4)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
1088#if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */
1089 else if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_IPV6))
1090 intnetR0IfSniffIPv6SourceAddr(pIf, (PCINTNETIPV6)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
1091#endif
1092#if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
1093 else if ( EtherType == RT_H2BE_U16(0x8037) //??
1094 || EtherType == RT_H2BE_U16(0x8137) //??
1095 || EtherType == RT_H2BE_U16(0x8138) //??
1096 )
1097 intnetR0IfSniffIpxSourceAddr(pIf, (PCINTNETIPX)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
1098#endif
1099 else if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_ARP))
1100 intnetR0IfSniffArpSourceAddr(pIf, (PCINTNETARPHDR)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
1101}
1102
1103
1104/**
1105 * Initializes a scatter / gather buffer from a simple linear buffer.
1106 *
1107 * @returns Pointer to the start of the frame.
1108 * @param pSG Pointer to the scatter / gather structure.
1109 * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
1110 * @param pvFrame Pointer to the frame
1111 * @param cbFrame The size of the frame.
1112 */
1113DECLINLINE(void) intnetR0SgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame)
1114{
1115 pSG->pvOwnerData = NULL;
1116 pSG->pvUserData = NULL;
1117 pSG->pvUserData2 = NULL;
1118 pSG->cbTotal = cbFrame;
1119 pSG->cUsers = 1;
1120 pSG->fFlags = INTNETSG_FLAGS_TEMP;
1121 pSG->cSegsAlloc = 1;
1122 pSG->cSegsUsed = 1;
1123 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
1124 pSG->aSegs[0].pv = pvFrame;
1125 pSG->aSegs[0].cb = cbFrame;
1126}
1127
1128
1129/**
1130 * Initializes a scatter / gather buffer from a internal networking packet.
1131 *
1132 * @returns Pointer to the start of the frame.
1133 * @param pSG Pointer to the scatter / gather structure.
1134 * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
1135 * @param pHdr Pointer to the packet header.
1136 * @param pBuf The buffer the header is within. Only used in strict builds.
1137 */
1138DECLINLINE(void) intnetR0SgInitFromPkt(PINTNETSG pSG, PCINTNETHDR pPktHdr, PCINTNETBUF pBuf)
1139{
1140 pSG->cSegsUsed = 1;
1141 pSG->cbTotal = pSG->aSegs[0].cb = pPktHdr->cbFrame;
1142 pSG->aSegs[0].pv = INTNETHdrGetFramePtr(pPktHdr, pBuf);
1143 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
1144}
1145
1146
1147#ifdef IN_INTNET_TESTCASE
1148/**
1149 * Reads the next frame in the buffer.
1150 * The caller is responsible for ensuring that there is a valid frame in the buffer.
1151 *
1152 * @returns Size of the frame in bytes.
1153 * @param pBuf The buffer.
1154 * @param pRingBuff The ring buffer to read from.
1155 * @param pvFrame Where to put the frame. The caller is responsible for
1156 * ensuring that there is sufficient space for the frame.
1157 */
1158static unsigned intnetR0RingReadFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, void *pvFrame)
1159{
1160 Assert(pRingBuf->offRead < pBuf->cbBuf);
1161 Assert(pRingBuf->offRead >= pRingBuf->offStart);
1162 Assert(pRingBuf->offRead < pRingBuf->offEnd);
1163 uint32_t offRead = pRingBuf->offRead;
1164 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offRead);
1165 const void *pvFrameIn = INTNETHdrGetFramePtr(pHdr, pBuf);
1166 unsigned cb = pHdr->cbFrame;
1167 memcpy(pvFrame, pvFrameIn, cb);
1168
1169 /* skip the frame */
1170 offRead += pHdr->offFrame + cb;
1171 offRead = RT_ALIGN_32(offRead, sizeof(INTNETHDR));
1172 Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
1173 if (offRead >= pRingBuf->offEnd)
1174 offRead = pRingBuf->offStart;
1175 ASMAtomicXchgU32(&pRingBuf->offRead, offRead);
1176 return cb;
1177}
1178#endif /* IN_INTNET_TESTCASE */
1179
1180
1181/**
1182 * Reads an entire SG into a fittingly size buffer.
1183 *
1184 * @param pSG The SG list to read.
1185 * @param pvBuf The buffer to read into (at least pSG->cbTotal in size).
1186 */
1187DECLINLINE(void) intnetR0SgRead(PCINTNETSG pSG, void *pvBuf)
1188{
1189 if (pSG->cSegsUsed == 1)
1190 {
1191 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
1192 memcpy(pvBuf, pSG->aSegs[0].pv, pSG->cbTotal);
1193 }
1194 else
1195 {
1196 uint8_t *pbDst = (uint8_t *)pvBuf;
1197 unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
1198 for (unsigned iSeg = 0; iSeg < cSegs; iSeg++)
1199 {
1200 uint32_t cbSeg = pSG->aSegs[iSeg].cb;
1201 Assert(cbSeg <= pSG->cbTotal && (uintptr_t)(pbDst - (uint8_t *)pvBuf) + cbSeg <= pSG->cbTotal);
1202 memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg);
1203 pbDst += cbSeg;
1204 }
1205 }
1206}
1207
1208
1209/**
1210 * Writes a frame packet to the buffer.
1211 *
1212 * @returns VBox status code.
1213 * @param pBuf The buffer.
1214 * @param pRingBuf The ring buffer to read from.
1215 * @param pSG The gatter list.
1216 */
1217static int intnetR0RingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, PCINTNETSG pSG)
1218{
1219 /*
1220 * Validate input.
1221 */
1222 AssertPtr(pBuf);
1223 AssertPtr(pRingBuf);
1224 AssertPtr(pSG);
1225 Assert(pSG->cbTotal >= sizeof(PDMMAC) * 2);
1226 uint32_t offWrite = pRingBuf->offWrite;
1227 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
1228 uint32_t offRead = pRingBuf->offRead;
1229 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
1230
1231 const uint32_t cb = RT_ALIGN_32(pSG->cbTotal, sizeof(INTNETHDR));
1232 if (offRead <= offWrite)
1233 {
1234 /*
1235 * Try fit it all before the end of the buffer.
1236 */
1237 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
1238 {
1239 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
1240 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
1241 pHdr->cbFrame = pSG->cbTotal;
1242 pHdr->offFrame = sizeof(INTNETHDR);
1243
1244 intnetR0SgRead(pSG, pHdr + 1);
1245
1246 offWrite += cb + sizeof(INTNETHDR);
1247 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
1248 if (offWrite >= pRingBuf->offEnd)
1249 offWrite = pRingBuf->offStart;
1250 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
1251 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
1252 return VINF_SUCCESS;
1253 }
1254
1255 /*
1256 * Try fit the frame at the start of the buffer.
1257 * (The header fits before the end of the buffer because of alignment.)
1258 */
1259 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
1260 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
1261 {
1262 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
1263 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
1264 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
1265 pHdr->cbFrame = pSG->cbTotal;
1266 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
1267
1268 intnetR0SgRead(pSG, pvFrameOut);
1269
1270 offWrite = pRingBuf->offStart + cb;
1271 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
1272 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
1273 return VINF_SUCCESS;
1274 }
1275 }
1276 /*
1277 * The reader is ahead of the writer, try fit it into that space.
1278 */
1279 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
1280 {
1281 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
1282 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
1283 pHdr->cbFrame = pSG->cbTotal;
1284 pHdr->offFrame = sizeof(INTNETHDR);
1285
1286 intnetR0SgRead(pSG, pHdr + 1);
1287
1288 offWrite += cb + sizeof(INTNETHDR);
1289 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
1290 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
1291 return VINF_SUCCESS;
1292 }
1293
1294 /* (it didn't fit) */
1295 /** @todo stats */
1296 return VERR_BUFFER_OVERFLOW;
1297}
1298
1299
1300/**
1301 * Sends a frame to a specific interface.
1302 *
1303 * @param pIf The interface.
1304 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
1305 * @param pSG The gather buffer which data is being sent to the interface.
1306 */
1307static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG)
1308{
1309// LogFlow(("intnetR0IfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
1310 int rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pSG);
1311 if (RT_SUCCESS(rc))
1312 {
1313 pIf->cYields = 0;
1314 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
1315 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, pSG->cbTotal);
1316 RTSemEventSignal(pIf->Event);
1317 return;
1318 }
1319
1320 Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf));
1321
1322#if 0 /* This is bad stuff now as we're blocking while locking down the network.
1323 we really shouldn't delay the network traffic on the host just because
1324 some bugger isn't responding. Will have to deal with this in a different
1325 manner if required. */
1326 /*
1327 * Retry a few times, yielding the CPU in between.
1328 * But don't let a unresponsive VM harm performance, so give up after a couple of tries.
1329 */
1330 if ( pIf->fActive
1331 && pIf->cYields < 100)
1332 {
1333 unsigned cYields = 10;
1334#else
1335 /*
1336 * Scheduling hack, for unicore machines primarily.
1337 */
1338 if ( pIf->fActive
1339 && pIf->cYields < 4 /* just twice */
1340 && pIfSender /* but not if it's from the trunk */)
1341 {
1342 unsigned cYields = 2;
1343#endif
1344 while (--cYields > 0)
1345 {
1346 RTSemEventSignal(pIf->Event);
1347 RTThreadYield();
1348 rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pSG);
1349 if (RT_SUCCESS(rc))
1350 {
1351 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
1352 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
1353 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, pSG->cbTotal);
1354 RTSemEventSignal(pIf->Event);
1355 return;
1356 }
1357 pIf->cYields++;
1358 }
1359 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
1360 }
1361
1362 /* ok, the frame is lost. */
1363 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
1364 RTSemEventSignal(pIf->Event);
1365}
1366
1367
1368/**
1369 * Sends a frame down the trunk.
1370 *
1371 * The caller must own the network mutex, might be abandond temporarily.
1372 * The fTrunkLock parameter indicates whether the trunk lock is held.
1373 *
1374 * @param pThis The trunk.
1375 * @param pNetwork The network the frame is being sent to.
1376 * @param fDst The destination flags.
1377 * @param pSG Pointer to the gather list.
1378 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
1379 */
1380static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, uint32_t fDst, PINTNETSG pSG, bool fTrunkLocked)
1381{
1382 /*
1383 * Quick sanity check.
1384 */
1385 AssertPtr(pThis);
1386 AssertPtr(pNetwork);
1387 AssertPtr(pSG);
1388 Assert(fDst);
1389 AssertReturnVoid(pThis->pIfPort);
1390
1391 /*
1392 * Temporarily leave the network lock while transmitting the frame.
1393 *
1394 * Note that we're relying on the out-bound lock to serialize threads down
1395 * in INTNETR0IfSend. It's theoretically possible for there to be race now
1396 * because I didn't implement async SG handling yet. Which is why we currently
1397 * require the trunk to be locked, well, one of the reasons.
1398 *
1399 * Another reason is that the intnetR0NetworkSendUnicast code may have to
1400 * call into the trunk interface component to do package switching.
1401 */
1402 AssertReturnVoid(fTrunkLocked); /* to be removed. */
1403
1404 int rc;
1405 if ( fTrunkLocked
1406 || intnetR0TrunkIfRetain(pThis))
1407 {
1408 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1409 AssertRC(rc);
1410 if (RT_SUCCESS(rc))
1411 {
1412 if ( fTrunkLocked
1413 || intnetR0TrunkIfOutLock(pThis))
1414 {
1415 rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst);
1416
1417 if (!fTrunkLocked)
1418 intnetR0TrunkIfOutUnlock(pThis);
1419 }
1420 else
1421 {
1422 AssertFailed();
1423 rc = VERR_SEM_DESTROYED;
1424 }
1425
1426 int rc2 = RTSemFastMutexRequest(pNetwork->FastMutex);
1427 AssertRC(rc2);
1428 }
1429
1430 if (!fTrunkLocked)
1431 intnetR0TrunkIfRelease(pThis);
1432 }
1433 else
1434 {
1435 AssertFailed();
1436 rc = VERR_SEM_DESTROYED;
1437 }
1438
1439 /** @todo failure statistics? */
1440 Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst));
1441}
1442
1443
1444/**
1445 * Sends a broadcast frame.
1446 *
1447 * The caller must own the network mutex, might be abandond temporarily.
1448 * When pIfSender is not NULL, the caller must also own the trunk semaphore.
1449 *
1450 * @returns true if it's addressed to someone on the network, otherwise false.
1451 * @param pNetwork The network the frame is being sent to.
1452 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
1453 * @param fSrc The source flags. This 0 if it's not from the trunk.
1454 * @param pSG Pointer to the gather list.
1455 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
1456 */
1457static bool intnetR0NetworkSendBroadcast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PINTNETSG pSG, bool fTrunkLocked)
1458{
1459 /*
1460 * This is a broadcast or multicast address. For the present we treat those
1461 * two as the same - investigating multicast is left for later.
1462 *
1463 * Write the packet to all the interfaces and signal them.
1464 */
1465 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
1466 if (pIf != pIfSender)
1467 intnetR0IfSend(pIf, pIfSender, pSG);
1468
1469 /*
1470 * Unless the trunk is the origin, broadcast it to both the wire
1471 * and the host as well.
1472 */
1473 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
1474 if ( pIfSender
1475 && pTrunkIf)
1476 intnetR0TrunkIfSend(pTrunkIf, pNetwork, INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked);
1477 return false; /* broadcast frames are never dropped */
1478}
1479
1480
1481/**
1482 * Sends a multicast frame.
1483 *
1484 * The caller must own the network mutex, might be abandond temporarily.
1485 *
1486 * @returns true if it's addressed to someone on the network, otherwise false.
1487 * @param pNetwork The network the frame is being sent to.
1488 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
1489 * @param fSrc The source flags. This 0 if it's not from the trunk.
1490 * @param pSG Pointer to the gather list.
1491 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
1492 * @param pEthHdr Pointer to the ethernet header.
1493 */
1494static bool intnetR0NetworkSendMulticast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCINTNETETHERHDR pEthHdr)
1495{
1496 /** @todo implement multicast */
1497 return intnetR0NetworkSendBroadcast(pNetwork, pIfSender, pSG, fTrunkLocked);
1498}
1499
1500
1501/**
1502 * Sends a unicast frame.
1503 *
1504 * The caller must own the network mutex, might be abandond temporarily.
1505 *
1506 * @returns true if it's addressed to someone on the network, otherwise false.
1507 * @param pNetwork The network the frame is being sent to.
1508 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
1509 * @param fSrc The source flags. This 0 if it's not from the trunk.
1510 * @param pSG Pointer to the gather list.
1511 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
1512 * @param pEthHdr Pointer to the ethernet header.
1513 */
1514static bool intnetR0NetworkSendUnicast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCINTNETETHERHDR pEthHdr)
1515{
1516 /*
1517 * Only send to the interfaces with matching a MAC address.
1518 */
1519 bool fExactIntNetRecipient = false;
1520 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
1521 {
1522 bool fIt = false;
1523 if ( ( !pIf->fMacSet
1524 || (fIt = !memcmp(&pIf->Mac, &pEthHdr->MacDst, sizeof(pIf->Mac))) )
1525 || ( pIf->fPromiscuous
1526 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
1527 && pIf != pIfSender /* promiscuous mode: omit the sender */))
1528 {
1529 Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->MacDst, &pIf->Mac));
1530 fExactIntNetRecipient |= fIt;
1531 intnetR0IfSend(pIf, pIfSender, pSG);
1532 }
1533 }
1534
1535 /*
1536 * Send it to the trunk?
1537 * If we didn't find the recipient on the internal network the
1538 * frame will hit the wire.
1539 */
1540 uint32_t fDst = 0;
1541 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
1542 if ( pIfSender
1543 && pTrunkIf
1544 && pTrunkIf->pIfPort)
1545 {
1546 /* promiscuous checks first as they are cheaper than pfnIsHostMac. */
1547 if ( pTrunkIf->fPromiscuousWire
1548 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE)) )
1549 fDst |= INTNETTRUNKDIR_WIRE;
1550 if ( !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST))
1551 || pTrunkIf->pIfPort->pfnIsPromiscuous(pTrunkIf->pIfPort) )
1552 fDst |= INTNETTRUNKDIR_HOST;
1553
1554 if ( fDst != (INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE)
1555 && !fExactIntNetRecipient /* if you have duplicate mac addresses, you're screwed. */ )
1556 {
1557 if (pTrunkIf->pIfPort->pfnIsHostMac(pTrunkIf->pIfPort, &pEthHdr->MacDst))
1558 fDst |= INTNETTRUNKDIR_HOST;
1559 else
1560 fDst |= INTNETTRUNKDIR_WIRE;
1561 }
1562
1563 if (fDst)
1564 intnetR0TrunkIfSend(pTrunkIf, pNetwork, fDst, pSG, fTrunkLocked);
1565 }
1566
1567 /* log it */
1568 if ( !fExactIntNetRecipient
1569 && !fDst
1570 && ( (pEthHdr->MacDst.au8[0] == 0x08 && pEthHdr->MacDst.au8[1] == 0x00 && pEthHdr->MacDst.au8[2] == 0x27)
1571 || (pEthHdr->MacSrc.au8[0] == 0x08 && pEthHdr->MacSrc.au8[1] == 0x00 && pEthHdr->MacSrc.au8[2] == 0x27)))
1572 Log2(("Dst=%.6Rhxs ??\n", &pEthHdr->MacDst));
1573
1574 return fExactIntNetRecipient;
1575}
1576
1577
1578/**
1579 * Sends a frame.
1580 *
1581 * This function will distribute the frame to the interfaces it is addressed to.
1582 * It will also update the MAC address of the sender.
1583 *
1584 * The caller must own the network mutex.
1585 *
1586 * @returns true if it's addressed to someone on the network, otherwise false.
1587 * @param pNetwork The network the frame is being sent to.
1588 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
1589 * @param fSrc The source flags. This 0 if it's not from the trunk.
1590 * @param pSG Pointer to the gather list.
1591 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
1592 */
1593static bool intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked)
1594{
1595 bool fRc = false;
1596
1597 /*
1598 * Assert reality.
1599 */
1600 AssertPtr(pNetwork);
1601 AssertPtrNull(pIfSender);
1602 Assert(pIfSender ? fSrc == 0 : fSrc != 0);
1603 Assert(!pIfSender || pNetwork == pIfSender->pNetwork);
1604 AssertPtr(pSG);
1605 Assert(pSG->cSegsUsed >= 1);
1606 Assert(pSG->cSegsUsed <= pSG->cSegsAlloc);
1607 if (pSG->cbTotal < sizeof(INTNETETHERHDR))
1608 return fRc;
1609
1610 /*
1611 * Send statistics.
1612 */
1613 if (pIfSender)
1614 {
1615 STAM_REL_COUNTER_INC(&pIfSender->pIntBuf->cStatSends);
1616 STAM_REL_COUNTER_ADD(&pIfSender->pIntBuf->cbStatSend, pSG->cbTotal);
1617 }
1618
1619 /*
1620 * Get the ethernet header (might theoretically involve multiple segments).
1621 */
1622 INTNETETHERHDR EthHdr;
1623 if (RT_LIKELY(pSG->aSegs[0].cb >= sizeof(EthHdr)))
1624 EthHdr = *(PCINTNETETHERHDR)pSG->aSegs[0].pv;
1625 else
1626 {
1627 uint8_t *pbDst = (uint8_t *)&EthHdr;
1628 size_t cbLeft = sizeof(EthHdr);
1629 for (unsigned iSeg = 0; cbLeft && iSeg < pSG->cSegsUsed; iSeg++)
1630 {
1631 size_t cb = RT_MIN(cbLeft, pSG->aSegs[iSeg].cb);
1632 memcpy(pbDst, pSG->aSegs[iSeg].pv, cb);
1633 pbDst += cb;
1634 cbLeft -= cb;
1635 }
1636 AssertReturn(!cbLeft, false);
1637 }
1638 if ( (EthHdr.MacDst.au8[0] == 0x08 && EthHdr.MacDst.au8[1] == 0x00 && EthHdr.MacDst.au8[2] == 0x27)
1639 || (EthHdr.MacSrc.au8[0] == 0x08 && EthHdr.MacSrc.au8[1] == 0x00 && EthHdr.MacSrc.au8[2] == 0x27)
1640 || (EthHdr.MacDst.au8[0] == 0x00 && EthHdr.MacDst.au8[1] == 0x16 && EthHdr.MacDst.au8[2] == 0xcb)
1641 || (EthHdr.MacSrc.au8[0] == 0x00 && EthHdr.MacSrc.au8[1] == 0x16 && EthHdr.MacSrc.au8[2] == 0xcb)
1642 || EthHdr.MacDst.au8[0] == 0xff
1643 || EthHdr.MacSrc.au8[0] == 0xff)
1644 Log2(("D=%.6Rhxs S=%.6Rhxs T=%04x f=%x z=%x\n",
1645 &EthHdr.MacDst, &EthHdr.MacSrc, RT_BE2H_U16(EthHdr.EtherType), fSrc, pSG->cbTotal));
1646
1647 /*
1648 * Inspect the header updating the mac address of the sender in the process.
1649 */
1650 if ( pIfSender
1651 && memcmp(&EthHdr.MacSrc, &pIfSender->Mac, sizeof(pIfSender->Mac)))
1652 {
1653 /** @todo stats */
1654 Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &EthHdr.MacSrc));
1655 pIfSender->Mac = EthHdr.MacSrc;
1656 pIfSender->fMacSet = true;
1657 }
1658
1659 /*
1660 * Distribute the frame.
1661 */
1662 if (RT_UNLIKELY(EthHdr.MacDst.au8[0] & 1)) /* multicast address */
1663 fRc = intnetR0NetworkSendMulticast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
1664 else if ( EthHdr.MacDst.au16[0] == 0xffff /* broadcast address. */
1665 && EthHdr.MacDst.au16[1] == 0xffff
1666 && EthHdr.MacDst.au16[2] == 0xffff)
1667 fRc = intnetR0NetworkSendBroadcast(pNetwork, pIfSender, pSG, fTrunkLocked);
1668 else
1669 fRc = intnetR0NetworkSendUnicast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
1670 return fRc;
1671}
1672
1673
1674/**
1675 * Sends one or more frames.
1676 *
1677 * The function will first the frame which is passed as the optional
1678 * arguments pvFrame and cbFrame. These are optional since it also
1679 * possible to chain together one or more frames in the send buffer
1680 * which the function will process after considering it's arguments.
1681 *
1682 * @returns VBox status code.
1683 * @param pIntNet The instance data.
1684 * @param hIf The interface handle.
1685 * @param pSession The caller's session.
1686 * @param pvFrame Pointer to the frame. Optional, please don't use.
1687 * @param cbFrame Size of the frame. Optional, please don't use.
1688 */
1689INTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, const void *pvFrame, unsigned cbFrame)
1690{
1691 Log5(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
1692
1693 /*
1694 * Validate input and translate the handle.
1695 */
1696 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1697 if (pvFrame && cbFrame)
1698 {
1699 AssertReturn(cbFrame < 0x8000, VERR_INVALID_PARAMETER);
1700 AssertPtrReturn(pvFrame, VERR_INVALID_PARAMETER);
1701 AssertPtrReturn((uint8_t *)pvFrame + cbFrame - 1, VERR_INVALID_PARAMETER);
1702
1703 /* This is the better place to crash, probe the buffer. */
1704 ASMProbeReadBuffer(pvFrame, cbFrame);
1705 }
1706 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1707 if (!pIf)
1708 return VERR_INVALID_HANDLE;
1709
1710 /*
1711 * Lock the network. If there is a trunk retain it and grab its
1712 * out-bound lock (this requires leaving the network lock first).
1713 * Grabbing the out-bound lock here simplifies things quite a bit
1714 * later on, so while this is excessive and a bit expensive it's
1715 * not worth caring about right now.
1716 */
1717 PINTNETNETWORK pNetwork = pIf->pNetwork;
1718 int rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1719 if (RT_FAILURE(rc))
1720 {
1721 intnetR0IfRelease(pIf, pSession);
1722 return rc;
1723 }
1724 PINTNETTRUNKIF pTrunkIf = intnetR0TrunkIfRetain(pNetwork->pTrunkIF);
1725 if (pTrunkIf)
1726 {
1727 RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1728
1729 if (!intnetR0TrunkIfOutLock(pTrunkIf))
1730 {
1731 intnetR0TrunkIfRelease(pTrunkIf);
1732 intnetR0IfRelease(pIf, pSession);
1733 return VERR_SEM_DESTROYED;
1734 }
1735
1736 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1737 if (RT_FAILURE(rc))
1738 {
1739 intnetR0TrunkIfOutUnlock(pTrunkIf);
1740 intnetR0TrunkIfRelease(pTrunkIf);
1741 intnetR0IfRelease(pIf, pSession);
1742 return rc;
1743 }
1744 }
1745
1746 INTNETSG Sg; /** @todo this will have to be changed if we're going to use async sending
1747 * with buffer sharing for some OS or service. Darwin copies everything so
1748 * I won't bother allocating and managing SGs rigth now. Sorry. */
1749
1750 /*
1751 * Process the argument.
1752 */
1753 if (pvFrame && cbFrame)
1754 {
1755 intnetR0SgInitTemp(&Sg, (void *)pvFrame, cbFrame);
1756 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
1757 }
1758
1759 /*
1760 * Process the send buffer.
1761 */
1762 while (pIf->pIntBuf->Send.offRead != pIf->pIntBuf->Send.offWrite)
1763 {
1764 /* Send the frame if the type is sane. */
1765 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pIf->pIntBuf + pIf->pIntBuf->Send.offRead);
1766 if (pHdr->u16Type == INTNETHDR_TYPE_FRAME)
1767 {
1768 void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
1769 if (pvCurFrame)
1770 {
1771 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
1772 intnetR0IfSniffSourceAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame);
1773 intnetR0SgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame);
1774 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
1775 }
1776 }
1777 /* else: ignore the frame */
1778
1779 /* Skip to the next frame. */
1780 INTNETRingSkipFrame(pIf->pIntBuf, &pIf->pIntBuf->Send);
1781 }
1782
1783 /*
1784 * Release the semaphore(s) and release references.
1785 */
1786 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1787 if (pTrunkIf)
1788 {
1789 intnetR0TrunkIfOutUnlock(pTrunkIf);
1790 intnetR0TrunkIfRelease(pTrunkIf);
1791 }
1792
1793 intnetR0IfRelease(pIf, pSession);
1794 return rc;
1795}
1796
1797
1798/**
1799 * VMMR0 request wrapper for INTNETR0IfSend.
1800 *
1801 * @returns see INTNETR0IfSend.
1802 * @param pIntNet The internal networking instance.
1803 * @param pSession The caller's session.
1804 * @param pReq The request packet.
1805 */
1806INTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq)
1807{
1808 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1809 return VERR_INVALID_PARAMETER;
1810 return INTNETR0IfSend(pIntNet, pReq->hIf, pSession, NULL, 0);
1811}
1812
1813
1814/**
1815 * Maps the default buffer into ring 3.
1816 *
1817 * @returns VBox status code.
1818 * @param pIntNet The instance data.
1819 * @param hIf The interface handle.
1820 * @param pSession The caller's session.
1821 * @param ppRing3Buf Where to store the address of the ring-3 mapping.
1822 */
1823INTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
1824{
1825 LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
1826
1827 /*
1828 * Validate input.
1829 */
1830 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1831 AssertPtrReturn(ppRing3Buf, VERR_INVALID_PARAMETER);
1832 *ppRing3Buf = 0;
1833 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1834 if (!pIf)
1835 return VERR_INVALID_HANDLE;
1836
1837 /*
1838 * ASSUMES that only the process that created an interface can use it.
1839 * ASSUMES that we created the ring-3 mapping when selecting or
1840 * allocating the buffer.
1841 */
1842 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
1843 if (RT_SUCCESS(rc))
1844 {
1845 *ppRing3Buf = pIf->pIntBufR3;
1846 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1847 }
1848
1849 intnetR0IfRelease(pIf, pSession);
1850 LogFlow(("INTNETR0IfGetRing3Buffer: returns %Rrc *ppRing3Buf=%p\n", rc, *ppRing3Buf));
1851 return rc;
1852}
1853
1854
1855/**
1856 * VMMR0 request wrapper for INTNETR0IfGetRing3Buffer.
1857 *
1858 * @returns see INTNETR0IfGetRing3Buffer.
1859 * @param pIntNet The internal networking instance.
1860 * @param pSession The caller's session.
1861 * @param pReq The request packet.
1862 */
1863INTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFGETRING3BUFFERREQ pReq)
1864{
1865 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1866 return VERR_INVALID_PARAMETER;
1867 return INTNETR0IfGetRing3Buffer(pIntNet, pReq->hIf, pSession, &pReq->pRing3Buf);
1868}
1869
1870
1871/**
1872 * Gets the ring-0 address of the current buffer.
1873 *
1874 * @returns VBox status code.
1875 * @param pIntNet The instance data.
1876 * @param hIf The interface handle.
1877 * @param pSession The caller's session.
1878 * @param ppRing0Buf Where to store the address of the ring-3 mapping.
1879 */
1880INTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF *ppRing0Buf)
1881{
1882 LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
1883
1884 /*
1885 * Validate input.
1886 */
1887 AssertPtrReturn(ppRing0Buf, VERR_INVALID_PARAMETER);
1888 *ppRing0Buf = NULL;
1889 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1890 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1891 if (!pIf)
1892 return VERR_INVALID_HANDLE;
1893
1894 /*
1895 * Grab the lock and get the data.
1896 * ASSUMES that the handle isn't closed while we're here.
1897 */
1898 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
1899 if (RT_SUCCESS(rc))
1900 {
1901 *ppRing0Buf = pIf->pIntBuf;
1902
1903 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1904 }
1905 intnetR0IfRelease(pIf, pSession);
1906 LogFlow(("INTNETR0IfGetRing0Buffer: returns %Rrc *ppRing0Buf=%p\n", rc, *ppRing0Buf));
1907 return rc;
1908}
1909
1910
1911#if 0
1912/**
1913 * Gets the physical addresses of the default interface buffer.
1914 *
1915 * @returns VBox status code.
1916 * @param pIntNet The instance data.
1917 * @param hIF The interface handle.
1918 * @param paPages Where to store the addresses. (The reserved fields will be set to zero.)
1919 * @param cPages
1920 */
1921INTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
1922{
1923 /*
1924 * Validate input.
1925 */
1926 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1927 AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
1928 AssertPtrReturn((uint8_t *)&paPages[cPages] - 1, VERR_INVALID_PARAMETER);
1929 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1930 if (!pIf)
1931 return VERR_INVALID_HANDLE;
1932
1933 /*
1934 * Grab the lock and get the data.
1935 * ASSUMES that the handle isn't closed while we're here.
1936 */
1937 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
1938 if (RT_SUCCESS(rc))
1939 {
1940 /** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there
1941 * is no need for any extra bookkeeping here.. */
1942
1943 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1944 }
1945 intnetR0IfRelease(pIf, pSession);
1946 return VERR_NOT_IMPLEMENTED;
1947}
1948#endif
1949
1950
1951/**
1952 * Sets the promiscuous mode property of an interface.
1953 *
1954 * @returns VBox status code.
1955 * @param pIntNet The instance handle.
1956 * @param hIf The interface handle.
1957 * @param pSession The caller's session.
1958 * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not.
1959 */
1960INTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous)
1961{
1962 LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
1963
1964 /*
1965 * Validate & translate input.
1966 */
1967 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1968 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1969 if (!pIf)
1970 {
1971 Log(("INTNETR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
1972 return VERR_INVALID_HANDLE;
1973 }
1974
1975 /*
1976 * Grab the network semaphore and make the change.
1977 */
1978 int rc;
1979 PINTNETNETWORK pNetwork = pIf->pNetwork;
1980 if (pNetwork)
1981 {
1982 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1983 if (RT_SUCCESS(rc))
1984 {
1985 if (pIf->fPromiscuous != fPromiscuous)
1986 {
1987 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
1988 hIf, !fPromiscuous, !!fPromiscuous));
1989 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);
1990 }
1991
1992 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1993 }
1994 }
1995 else
1996 rc = VERR_WRONG_ORDER;
1997
1998 intnetR0IfRelease(pIf, pSession);
1999 return rc;
2000}
2001
2002
2003/**
2004 * VMMR0 request wrapper for INTNETR0IfSetPromiscuousMode.
2005 *
2006 * @returns see INTNETR0IfSetPromiscuousMode.
2007 * @param pIntNet The internal networking instance.
2008 * @param pSession The caller's session.
2009 * @param pReq The request packet.
2010 */
2011INTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
2012{
2013 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2014 return VERR_INVALID_PARAMETER;
2015 return INTNETR0IfSetPromiscuousMode(pIntNet, pReq->hIf, pSession, pReq->fPromiscuous);
2016}
2017
2018
2019/**
2020 * Sets the MAC address of an interface.
2021 *
2022 * @returns VBox status code.
2023 * @param pIntNet The instance handle.
2024 * @param hIf The interface handle.
2025 * @param pSession The caller's session.
2026 * @param pMAC The new MAC address.
2027 */
2028INTNETR0DECL(int) INTNETR0IfSetMacAddress(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCPDMMAC pMac)
2029{
2030 LogFlow(("INTNETR0IfSetMacAddress: pIntNet=%p hIf=%RX32 pMac=%p:{%.6Rhxs}\n", pIntNet, hIf, pMac, pMac));
2031
2032 /*
2033 * Validate & translate input.
2034 */
2035 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2036 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
2037 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
2038 if (!pIf)
2039 {
2040 Log(("INTNETR0IfSetMacAddress: returns VERR_INVALID_HANDLE\n"));
2041 return VERR_INVALID_HANDLE;
2042 }
2043
2044 /*
2045 * Grab the network semaphore and make the change.
2046 */
2047 int rc;
2048 PINTNETNETWORK pNetwork = pIf->pNetwork;
2049 if (pNetwork)
2050 {
2051 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
2052 if (RT_SUCCESS(rc))
2053 {
2054 if (memcmp(&pIf->Mac, pMac, sizeof(pIf->Mac)))
2055 {
2056 Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
2057 hIf, &pIf->Mac, pMac));
2058 pIf->Mac = *pMac;
2059 pIf->fMacSet = true;
2060 }
2061
2062 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
2063 }
2064 }
2065 else
2066 rc = VERR_WRONG_ORDER;
2067
2068 intnetR0IfRelease(pIf, pSession);
2069 return rc;
2070}
2071
2072
2073/**
2074 * VMMR0 request wrapper for INTNETR0IfSetMacAddress.
2075 *
2076 * @returns see INTNETR0IfSetMacAddress.
2077 * @param pIntNet The internal networking instance.
2078 * @param pSession The caller's session.
2079 * @param pReq The request packet.
2080 */
2081INTNETR0DECL(int) INTNETR0IfSetMacAddressReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq)
2082{
2083 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2084 return VERR_INVALID_PARAMETER;
2085 return INTNETR0IfSetMacAddress(pIntNet, pReq->hIf, pSession, &pReq->Mac);
2086}
2087
2088
2089/**
2090 * Worker for intnetR0IfSetActive.
2091 *
2092 * This function will update the active interface count on the network and
2093 * activate or deactivate the trunk connection if necessary. Note that in
2094 * order to do this it is necessary to abandond the network semaphore.
2095 *
2096 * @returns VBox status code.
2097 * @param pNetwork The network.
2098 * @param fIf The interface.
2099 * @param fActive What to do.
2100 */
2101static int intnetR0NetworkSetIfActive(PINTNETNETWORK pNetwork, PINTNETIF pIf, bool fActive)
2102{
2103 /* quick santiy check */
2104 AssertPtr(pNetwork);
2105 AssertPtr(pIf);
2106
2107 /*
2108 * If we've got a trunk, lock it now in case we need to call out, and
2109 * then lock the network.
2110 */
2111 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
2112 if (pTrunkIf && !intnetR0TrunkIfOutLock(pTrunkIf))
2113 return VERR_SEM_DESTROYED;
2114
2115 int rc = RTSemFastMutexRequest(pNetwork->FastMutex); AssertRC(rc);
2116 if (RT_SUCCESS(rc))
2117 {
2118 bool fNetworkLocked = true;
2119
2120 /*
2121 * Make the change if necessary.
2122 */
2123 if (pIf->fActive != fActive)
2124 {
2125 pIf->fActive = fActive;
2126
2127 uint32_t const cActiveIFs = pNetwork->cActiveIFs;
2128 Assert((int32_t)cActiveIFs + (fActive ? 1 : -1) >= 0);
2129 pNetwork->cActiveIFs += fActive ? 1 : -1;
2130
2131 if ( pTrunkIf
2132 && ( !pNetwork->cActiveIFs
2133 || !cActiveIFs))
2134 {
2135 /*
2136 * We'll have to change the trunk status, so, leave
2137 * the network semaphore so we don't create any deadlocks.
2138 */
2139 int rc2 = RTSemFastMutexRelease(pNetwork->FastMutex); AssertRC(rc2);
2140 fNetworkLocked = false;
2141
2142 if (pTrunkIf->pIfPort)
2143 pTrunkIf->pIfPort->pfnSetActive(pTrunkIf->pIfPort, fActive);
2144 }
2145 }
2146
2147 if (fNetworkLocked)
2148 RTSemFastMutexRelease(pNetwork->FastMutex);
2149 }
2150 if (pTrunkIf)
2151 intnetR0TrunkIfOutUnlock(pTrunkIf);
2152 return rc;
2153}
2154
2155
2156/**
2157 * Activates or deactivates a interface.
2158 *
2159 * This is used to enable and disable the trunk connection on demans as well as
2160 * know when not to expect an interface to want to receive packets.
2161 *
2162 * @returns VBox status code.
2163 * @param pIf The interface.
2164 * @param fActive What to do.
2165 */
2166static int intnetR0IfSetActive(PINTNETIF pIf, bool fActive)
2167{
2168 /* quick sanity check */
2169 AssertPtrReturn(pIf, VERR_INVALID_POINTER);
2170
2171 /*
2172 * Hand it to the network since it might involve the trunk
2173 * and things are tricky there wrt to locking order.
2174 */
2175 PINTNETNETWORK pNetwork = pIf->pNetwork;
2176 if (!pNetwork)
2177 return VERR_WRONG_ORDER;
2178 return intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
2179}
2180
2181
2182/**
2183 * Sets the active property of an interface.
2184 *
2185 * @returns VBox status code.
2186 * @param pIntNet The instance handle.
2187 * @param hIf The interface handle.
2188 * @param pSession The caller's session.
2189 * @param fActive The new state.
2190 */
2191INTNETR0DECL(int) INTNETR0IfSetActive(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive)
2192{
2193 LogFlow(("INTNETR0IfSetActive: pIntNet=%p hIf=%RX32 fActive=%RTbool\n", pIntNet, hIf, fActive));
2194
2195 /*
2196 * Validate & translate input.
2197 */
2198 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2199 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
2200 if (!pIf)
2201 {
2202 Log(("INTNETR0IfSetActive: returns VERR_INVALID_HANDLE\n"));
2203 return VERR_INVALID_HANDLE;
2204 }
2205
2206 /*
2207 * Hand it to the network since it might involve the trunk
2208 * and things are tricky there wrt to locking order.
2209 */
2210 int rc;
2211 PINTNETNETWORK pNetwork = pIf->pNetwork;
2212 if (pNetwork)
2213 rc = intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
2214 else
2215 rc = VERR_WRONG_ORDER;
2216
2217 intnetR0IfRelease(pIf, pSession);
2218 return rc;
2219}
2220
2221
2222/**
2223 * VMMR0 request wrapper for INTNETR0IfSetActive.
2224 *
2225 * @returns see INTNETR0IfSetActive.
2226 * @param pIntNet The internal networking instance.
2227 * @param pSession The caller's session.
2228 * @param pReq The request packet.
2229 */
2230INTNETR0DECL(int) INTNETR0IfSetActiveReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq)
2231{
2232 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2233 return VERR_INVALID_PARAMETER;
2234 return INTNETR0IfSetActive(pIntNet, pReq->hIf, pSession, pReq->fActive);
2235}
2236
2237
2238/**
2239 * Wait for the interface to get signaled.
2240 * The interface will be signaled when is put into the receive buffer.
2241 *
2242 * @returns VBox status code.
2243 * @param pIntNet The instance handle.
2244 * @param hIf The interface handle.
2245 * @param pSession The caller's session.
2246 * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be
2247 * used if indefinite wait is desired.
2248 */
2249INTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies)
2250{
2251 Log4(("INTNETR0IfWait: pIntNet=%p hIf=%RX32 cMillies=%u\n", pIntNet, hIf, cMillies));
2252
2253 /*
2254 * Get and validate essential handles.
2255 */
2256 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2257 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
2258 if (!pIf)
2259 {
2260 Log(("INTNETR0IfWait: returns VERR_INVALID_HANDLE\n"));
2261 return VERR_INVALID_HANDLE;
2262 }
2263 const INTNETIFHANDLE hIfSelf = pIf->hIf;
2264 const RTSEMEVENT Event = pIf->Event;
2265 if ( hIfSelf != hIf /* paranoia */
2266 && Event != NIL_RTSEMEVENT)
2267 {
2268 Log(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
2269 return VERR_SEM_DESTROYED;
2270 }
2271
2272 /*
2273 * It is tempting to check if there is data to be read here,
2274 * but the problem with such an approach is that it will cause
2275 * one unnecessary supervisor->user->supervisor trip. There is
2276 * already a slight risk for such, so no need to increase it.
2277 */
2278
2279 /*
2280 * Increment the number of waiters before starting the wait.
2281 * Upon wakeup we must assert reality, checking that we're not
2282 * already destroyed or in the process of being destroyed. This
2283 * code must be aligned with the waiting code in intnetR0IfDestruct.
2284 */
2285 ASMAtomicIncU32(&pIf->cSleepers);
2286 int rc = RTSemEventWaitNoResume(Event, cMillies);
2287 if (pIf->Event == Event)
2288 {
2289 ASMAtomicDecU32(&pIf->cSleepers);
2290 if (!pIf->fDestroying)
2291 {
2292 intnetR0IfRelease(pIf, pSession);
2293 if (pIf->hIf != hIf)
2294 rc = VERR_SEM_DESTROYED;
2295 }
2296 else
2297 rc = VERR_SEM_DESTROYED;
2298 }
2299 else
2300 rc = VERR_SEM_DESTROYED;
2301 Log4(("INTNETR0IfWait: returns %Rrc\n", rc));
2302 return rc;
2303}
2304
2305
2306/**
2307 * VMMR0 request wrapper for INTNETR0IfWait.
2308 *
2309 * @returns see INTNETR0IfWait.
2310 * @param pIntNet The internal networking instance.
2311 * @param pSession The caller's session.
2312 * @param pReq The request packet.
2313 */
2314INTNETR0DECL(int) INTNETR0IfWaitReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq)
2315{
2316 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2317 return VERR_INVALID_PARAMETER;
2318 return INTNETR0IfWait(pIntNet, pReq->hIf, pSession, pReq->cMillies);
2319}
2320
2321
2322/**
2323 * Close an interface.
2324 *
2325 * @returns VBox status code.
2326 * @param pIntNet The instance handle.
2327 * @param hIf The interface handle.
2328 * @param pSession The caller's session.
2329 */
2330INTNETR0DECL(int) INTNETR0IfClose(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession)
2331{
2332 LogFlow(("INTNETR0IfClose: pIntNet=%p hIf=%RX32\n", pIntNet, hIf));
2333
2334 /*
2335 * Validate and free the handle.
2336 */
2337 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2338 PINTNETIF pIf = (PINTNETIF)RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pSession);
2339 if (!pIf)
2340 return VERR_INVALID_HANDLE;
2341
2342 /* mark the handle as freed so intnetR0IfDestruct won't free it again. */
2343 ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
2344
2345
2346 /*
2347 * Release the references to the interface object (handle + free lookup).
2348 * But signal the event semaphore first so any waiter holding a reference
2349 * will wake up too (he'll see hIf == invalid and return correctly).
2350 */
2351 RTSemEventSignal(pIf->Event);
2352
2353 void *pvObj = pIf->pvObj;
2354 intnetR0IfRelease(pIf, pSession); /* (RTHandleTableFreeWithCtx) */
2355
2356 int rc = SUPR0ObjRelease(pvObj, pSession);
2357 LogFlow(("INTNETR0IfClose: returns %Rrc\n", rc));
2358 return rc;
2359}
2360
2361
2362/**
2363 * VMMR0 request wrapper for INTNETR0IfCloseReq.
2364 *
2365 * @returns see INTNETR0IfClose.
2366 * @param pIntNet The internal networking instance.
2367 * @param pSession The caller's session.
2368 * @param pReq The request packet.
2369 */
2370INTNETR0DECL(int) INTNETR0IfCloseReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq)
2371{
2372 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2373 return VERR_INVALID_PARAMETER;
2374 return INTNETR0IfClose(pIntNet, pReq->hIf, pSession);
2375}
2376
2377
2378/**
2379 * Interface destructor callback.
2380 * This is called for reference counted objectes when the count reaches 0.
2381 *
2382 * @param pvObj The object pointer.
2383 * @param pvUser1 Pointer to the interface.
2384 * @param pvUser2 Pointer to the INTNET instance data.
2385 */
2386static DECLCALLBACK(void) intnetR0IfDestruct(void *pvObj, void *pvUser1, void *pvUser2)
2387{
2388 PINTNETIF pIf = (PINTNETIF)pvUser1;
2389 PINTNET pIntNet = (PINTNET)pvUser2;
2390 Log(("intnetR0IfDestruct: pvObj=%p pIf=%p pIntNet=%p hIf=%RX32\n", pvObj, pIf, pIntNet, pIf->hIf));
2391
2392 RTSemFastMutexRequest(pIntNet->FastMutex);
2393
2394 /*
2395 * Mark the interface as being destroyed so the waiter
2396 * can behave appropriately (theoretical case).
2397 */
2398 ASMAtomicWriteBool(&pIf->fDestroying, true);
2399
2400 /*
2401 * Delete the interface handle so the object no longer can be used.
2402 * (Can happen if the client didn't close its session.)
2403 */
2404 INTNETIFHANDLE hIf = ASMAtomicXchgU32(&pIf->hIf, INTNET_HANDLE_INVALID);
2405 if (hIf != INTNET_HANDLE_INVALID)
2406 {
2407 void *pvObj2 = RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pIf->pSession);
2408 AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%RX32 pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));
2409 }
2410
2411 /*
2412 * If we've got a network deactivate and unlink ourselves from it.
2413 * Because of cleanup order we might be an orphan now.
2414 */
2415 PINTNETNETWORK pNetwork = pIf->pNetwork;
2416 if (pNetwork)
2417 {
2418 intnetR0IfSetActive(pIf, false);
2419
2420 if (pNetwork->pIFs == pIf)
2421 pNetwork->pIFs = pIf->pNext;
2422 else
2423 {
2424 PINTNETIF pPrev = pNetwork->pIFs;
2425 while (pPrev)
2426 {
2427 if (pPrev->pNext == pIf)
2428 {
2429 pPrev->pNext = pIf->pNext;
2430 break;
2431 }
2432 pPrev = pPrev->pNext;
2433 }
2434 Assert(pPrev);
2435 }
2436 pIf->pNext = NULL;
2437
2438 /*
2439 * Release our reference to the network.
2440 */
2441 RTSemFastMutexRelease(pIntNet->FastMutex);
2442
2443 SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
2444 pIf->pNetwork = NULL;
2445 }
2446 else
2447 RTSemFastMutexRelease(pIntNet->FastMutex);
2448
2449 /*
2450 * Wakeup anyone waiting on this interface.
2451 *
2452 * We *must* make sure they have woken up properly and realized
2453 * that the interface is no longer valid.
2454 */
2455 if (pIf->Event != NIL_RTSEMEVENT)
2456 {
2457 RTSEMEVENT Event = pIf->Event;
2458 unsigned cMaxWait = 0x1000;
2459 while (pIf->cSleepers && cMaxWait-- > 0)
2460 {
2461 RTSemEventSignal(Event);
2462 RTThreadYield();
2463 }
2464 if (pIf->cSleepers)
2465 {
2466 RTThreadSleep(1);
2467
2468 cMaxWait = pIf->cSleepers;
2469 while (pIf->cSleepers && cMaxWait-- > 0)
2470 {
2471 RTSemEventSignal(Event);
2472 RTThreadSleep(10);
2473 }
2474 }
2475
2476 RTSemEventDestroy(Event);
2477 pIf->Event = NIL_RTSEMEVENT;
2478 }
2479
2480 /*
2481 * Unmap user buffer.
2482 */
2483 if (pIf->pIntBuf != pIf->pIntBufDefault)
2484 {
2485 /** @todo user buffer */
2486 }
2487
2488 /*
2489 * Unmap and Free the default buffer.
2490 */
2491 if (pIf->pIntBufDefault)
2492 {
2493 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
2494 pIf->pIntBufDefault = NULL;
2495 pIf->pIntBufDefaultR3 = 0;
2496 pIf->pIntBuf = NULL;
2497 pIf->pIntBufR3 = 0;
2498 }
2499
2500 /*
2501 * The interface.
2502 */
2503 pIf->pvObj = NULL;
2504 RTMemFree(pIf);
2505}
2506
2507
2508/**
2509 * Creates a new network interface.
2510 *
2511 * The call must have opened the network for the new interface
2512 * and is responsible for closing it on failure. On success
2513 * it must leave the network opened so the interface destructor
2514 * can close it.
2515 *
2516 * @returns VBox status code.
2517 * @param pNetwork The network.
2518 * @param pSession The session handle.
2519 * @param cbSend The size of the send buffer.
2520 * @param cbRecv The size of the receive buffer.
2521 * @param phIf Where to store the interface handle.
2522 */
2523static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf)
2524{
2525 LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u phIf=%p\n",
2526 pNetwork, pSession, cbSend, cbRecv, phIf));
2527
2528 /*
2529 * Assert input.
2530 */
2531 AssertPtr(pNetwork);
2532 AssertPtr(phIf);
2533 AssertPtr(pfCloseNetwork);
2534 *pfCloseNetwork = false;
2535
2536 /*
2537 * Allocate and initialize the interface structure.
2538 */
2539 PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
2540 if (!pIf)
2541 return VERR_NO_MEMORY;
2542 //pIf->pNext = NULL;
2543 memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */
2544 //pIf->fMacSet = false;
2545 //pIf->fPromiscuous = false;
2546 //pIf->fActive = false;
2547 //pIf->fDestroying = false;
2548 //pIf->pIntBuf = 0;
2549 //pIf->pIntBufR3 = NIL_RTR3PTR;
2550 //pIf->pIntBufDefault = 0;
2551 //pIf->pIntBufDefaultR3 = NIL_RTR3PTR;
2552 //pIf->cYields = 0;
2553 pIf->Event = NIL_RTSEMEVENT;
2554 //pIf->cSleepers = 0;
2555 pIf->hIf = INTNET_HANDLE_INVALID;
2556 pIf->pNetwork = pNetwork;
2557 pIf->pSession = pSession;
2558 //pIf->pvObj = NULL;
2559 int rc = RTSemEventCreate((PRTSEMEVENT)&pIf->Event);
2560 if (RT_SUCCESS(rc))
2561 {
2562 /*
2563 * Create the default buffer.
2564 */
2565 /** @todo adjust with minimums and apply defaults here. */
2566 cbRecv = RT_ALIGN(RT_MAX(cbRecv, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
2567 cbSend = RT_ALIGN(RT_MAX(cbSend, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
2568 const unsigned cbBuf = RT_ALIGN(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR)) + cbRecv + cbSend;
2569 rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
2570 if (RT_SUCCESS(rc))
2571 {
2572 ASMMemZero32(pIf->pIntBufDefault, cbBuf); /** @todo I thought I specified these buggers as clearing the memory... */
2573
2574 pIf->pIntBuf = pIf->pIntBufDefault;
2575 pIf->pIntBufR3 = pIf->pIntBufDefaultR3;
2576 pIf->pIntBuf->cbBuf = cbBuf;
2577 pIf->pIntBuf->cbRecv = cbRecv;
2578 pIf->pIntBuf->cbSend = cbSend;
2579 /* receive ring buffer. */
2580 pIf->pIntBuf->Recv.offStart = RT_ALIGN_32(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR));
2581 pIf->pIntBuf->Recv.offRead = pIf->pIntBuf->Recv.offStart;
2582 pIf->pIntBuf->Recv.offWrite = pIf->pIntBuf->Recv.offStart;
2583 pIf->pIntBuf->Recv.offEnd = pIf->pIntBuf->Recv.offStart + cbRecv;
2584 /* send ring buffer. */
2585 pIf->pIntBuf->Send.offStart = pIf->pIntBuf->Recv.offEnd;
2586 pIf->pIntBuf->Send.offRead = pIf->pIntBuf->Send.offStart;
2587 pIf->pIntBuf->Send.offWrite = pIf->pIntBuf->Send.offStart;
2588 pIf->pIntBuf->Send.offEnd = pIf->pIntBuf->Send.offStart + cbSend;
2589
2590 /*
2591 * Link the interface to the network.
2592 */
2593 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
2594 if (RT_SUCCESS(rc))
2595 {
2596 pIf->pNext = pNetwork->pIFs;
2597 pNetwork->pIFs = pIf;
2598 RTSemFastMutexRelease(pNetwork->FastMutex);
2599
2600 /*
2601 * Register the interface with the session.
2602 */
2603 pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet);
2604 if (pIf->pvObj)
2605 {
2606 rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf);
2607 if (RT_SUCCESS(rc))
2608 {
2609 *phIf = pIf->hIf;
2610 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
2611 *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
2612 return VINF_SUCCESS;
2613 }
2614
2615 SUPR0ObjRelease(pIf->pvObj, pSession);
2616 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
2617 return rc;
2618 }
2619
2620 RTSemFastMutexDestroy(pNetwork->FastMutex);
2621 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
2622 }
2623
2624 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
2625 pIf->pIntBufDefault = NULL;
2626 pIf->pIntBuf = NULL;
2627 }
2628
2629 RTSemEventDestroy(pIf->Event);
2630 pIf->Event = NIL_RTSEMEVENT;
2631 }
2632 RTMemFree(pIf);
2633 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
2634 *pfCloseNetwork = true;
2635 return rc;
2636}
2637
2638
2639
2640
2641
2642/** @copydoc INTNETTRUNKSWPORT::pfnSetSGPhys */
2643static DECLCALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
2644{
2645 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
2646 AssertMsgFailed(("Not implemented because it wasn't required on Darwin\n"));
2647 return ASMAtomicXchgBool(&pThis->fPhysSG, fEnable);
2648}
2649
2650
2651/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
2652static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
2653{
2654 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
2655 PINTNETNETWORK pNetwork = pThis->pNetwork;
2656
2657 /* assert some sanity */
2658 AssertPtrReturn(pNetwork, false);
2659 AssertReturn(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX, false);
2660 AssertPtr(pSG);
2661 Assert(fSrc);
2662
2663 /*
2664 * Lock the network and send the frame to it.
2665 */
2666 int rc = RTSemFastMutexRequest(pNetwork->FastMutex);
2667 AssertRCReturn(rc, false);
2668
2669 bool fRc;
2670 if (RT_LIKELY(pNetwork->cActiveIFs > 0))
2671 fRc = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, false /* fTrunkLocked */);
2672 else
2673 fRc = false; /* don't drop it */
2674
2675 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
2676 AssertRC(rc);
2677
2678 return fRc;
2679}
2680
2681
2682/** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */
2683static DECLCALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
2684{
2685 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
2686 PINTNETNETWORK pNetwork = pThis->pNetwork;
2687
2688 /* assert some sanity */
2689 AssertPtrReturnVoid(pNetwork);
2690 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
2691 AssertPtr(pSG);
2692 Assert(pSG->cUsers > 0);
2693
2694 /* do it. */
2695 ++pSG->cUsers;
2696}
2697
2698
2699/** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */
2700static DECLCALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
2701{
2702 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
2703 PINTNETNETWORK pNetwork = pThis->pNetwork;
2704
2705 /* assert some sanity */
2706 AssertPtrReturnVoid(pNetwork);
2707 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
2708 AssertPtr(pSG);
2709 Assert(pSG->cUsers > 0);
2710
2711 /*
2712 * Free it?
2713 */
2714 if (!--pSG->cUsers)
2715 {
2716 /** @todo later */
2717 }
2718}
2719
2720
2721/**
2722 * Retain the trunk interface.
2723 *
2724 * @returns pThis if retained.
2725 *
2726 * @param pThis The trunk.
2727 *
2728 * @remarks Any locks.
2729 */
2730static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis)
2731{
2732 if (pThis && pThis->pIfPort)
2733 {
2734 pThis->pIfPort->pfnRetain(pThis->pIfPort);
2735 return pThis;
2736 }
2737 return NULL;
2738}
2739
2740
2741/**
2742 * Release the trunk interface.
2743 *
2744 * @param pThis The trunk.
2745 */
2746static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis)
2747{
2748 if (pThis && pThis->pIfPort)
2749 pThis->pIfPort->pfnRelease(pThis->pIfPort);
2750}
2751
2752
2753/**
2754 * Takes the out-bound trunk lock.
2755 *
2756 * This will ensure that pIfPort is valid.
2757 *
2758 * @returns success indicator.
2759 * @param pThis The trunk.
2760 *
2761 * @remarks No locks other than the create/destroy one.
2762 */
2763static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis)
2764{
2765 AssertPtrReturn(pThis, false);
2766 int rc = RTSemFastMutexRequest(pThis->FastMutex);
2767 if (RT_SUCCESS(rc))
2768 {
2769 if (RT_LIKELY(pThis->pIfPort))
2770 return true;
2771 RTSemFastMutexRelease(pThis->FastMutex);
2772 }
2773 else
2774 AssertMsg(rc == VERR_SEM_DESTROYED, ("%Rrc\n", rc));
2775 return false;
2776}
2777
2778
2779/**
2780 * Releases the out-bound trunk lock.
2781 *
2782 * @param pThis The trunk.
2783 */
2784static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis)
2785{
2786 if (pThis)
2787 {
2788 int rc = RTSemFastMutexRelease(pThis->FastMutex);
2789 AssertRC(rc);
2790 }
2791}
2792
2793
2794/**
2795 * Activates the trunk interface.
2796 *
2797 * @param pThis The trunk.
2798 * @param fActive What to do with it.
2799 *
2800 * @remarks Caller may only own the create/destroy lock.
2801 */
2802static void intnetR0TrunkIfActivate(PINTNETTRUNKIF pThis, bool fActive)
2803{
2804 if (intnetR0TrunkIfOutLock(pThis))
2805 {
2806 pThis->pIfPort->pfnSetActive(pThis->pIfPort, fActive);
2807 intnetR0TrunkIfOutUnlock(pThis);
2808 }
2809}
2810
2811
2812/**
2813 * Shutdown the trunk interface.
2814 *
2815 * @param pThis The trunk.
2816 * @param pNetworks The network.
2817 *
2818 * @remarks The caller must *NOT* hold the network lock. The global
2819 * create/destroy lock is fine though.
2820 */
2821static void intnetR0TrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork)
2822{
2823 /* assert sanity */
2824 if (!pThis)
2825 return;
2826 AssertPtr(pThis);
2827 Assert(pThis->pNetwork == pNetwork);
2828 AssertPtrNull(pThis->pIfPort);
2829
2830 /*
2831 * The interface has already been deactivated, we just to wait for
2832 * it to become idle before we can disconnect and release it.
2833 */
2834 PINTNETTRUNKIFPORT pIfPort = pThis->pIfPort;
2835 if (pIfPort)
2836 {
2837 intnetR0TrunkIfOutLock(pThis);
2838
2839 /* unset it */
2840 pThis->pIfPort = NULL;
2841
2842 /* wait in portions so we can complain ever now an then. */
2843 uint64_t StartTS = RTTimeSystemNanoTS();
2844 int rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
2845 if (RT_FAILURE(rc))
2846 {
2847 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
2848 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2849 Assert(rc == VERR_TIMEOUT);
2850 while ( RT_FAILURE(rc)
2851 && RTTimeSystemNanoTS() - StartTS < UINT64_C(30000000000)) /* 30 sec */
2852 rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
2853 if (rc == VERR_TIMEOUT)
2854 {
2855 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
2856 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2857 while ( rc == VERR_TIMEOUT
2858 && RTTimeSystemNanoTS() - StartTS < UINT64_C(360000000000)) /* 360 sec */
2859 rc = pIfPort->pfnWaitForIdle(pIfPort, 30*1000);
2860 if (RT_FAILURE(rc))
2861 {
2862 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc), giving up.\n",
2863 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2864 AssertRC(rc);
2865 }
2866 }
2867 }
2868
2869 /* disconnect & release it. */
2870 pIfPort->pfnDisconnectAndRelease(pIfPort);
2871 }
2872
2873 /*
2874 * Free up the resources.
2875 */
2876 RTSEMFASTMUTEX FastMutex = pThis->FastMutex;
2877 pThis->FastMutex = NIL_RTSEMFASTMUTEX;
2878 pThis->pNetwork = NULL;
2879 RTSemFastMutexRelease(FastMutex);
2880 RTSemFastMutexDestroy(FastMutex);
2881 RTMemFree(pThis);
2882}
2883
2884
2885/**
2886 * Creates the trunk connection (if any).
2887 *
2888 * @returns VBox status code.
2889 *
2890 * @param pNetwork The newly created network.
2891 * @param pSession The session handle.
2892 */
2893static int intnetR0NetworkCreateTrunkIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
2894{
2895 const char *pszName;
2896 switch (pNetwork->enmTrunkType)
2897 {
2898 /*
2899 * The 'None' case, simple.
2900 */
2901 case kIntNetTrunkType_None:
2902 case kIntNetTrunkType_WhateverNone:
2903 return VINF_SUCCESS;
2904
2905 /* Can't happen, but makes GCC happy. */
2906 default:
2907 return VERR_NOT_IMPLEMENTED;
2908
2909 /*
2910 * Translate enum to component factory name.
2911 */
2912 case kIntNetTrunkType_NetFlt:
2913 pszName = "VBoxNetFlt";
2914 break;
2915 case kIntNetTrunkType_NetTap:
2916 pszName = "VBoxNetTap";
2917 break;
2918 case kIntNetTrunkType_SrvNat:
2919 pszName = "VBoxSrvNat";
2920 break;
2921 }
2922
2923 /*
2924 * Allocate the trunk interface.
2925 */
2926 PINTNETTRUNKIF pTrunkIF = (PINTNETTRUNKIF)RTMemAllocZ(sizeof(*pTrunkIF));
2927 if (!pTrunkIF)
2928 return VERR_NO_MEMORY;
2929 pTrunkIF->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION;
2930 pTrunkIF->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys;
2931 pTrunkIF->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv;
2932 pTrunkIF->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain;
2933 pTrunkIF->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease;
2934 pTrunkIF->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION;
2935 //pTrunkIF->pIfPort = NULL;
2936 pTrunkIF->pNetwork = pNetwork;
2937 //pTrunkIF->fPhysSG = false;
2938 //pTrunkIF->fPromiscuousWire = false;
2939 int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex);
2940 if (RT_SUCCESS(rc))
2941 {
2942#ifdef IN_RING0 /* (testcase is ring-3) */
2943 /*
2944 * Query the factory we want, then use it create and connect the trunk.
2945 */
2946 PINTNETTRUNKFACTORY pTrunkFactory = NULL;
2947 rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
2948 if (RT_SUCCESS(rc))
2949 {
2950 rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort, &pTrunkIF->pIfPort);
2951 pTrunkFactory->pfnRelease(pTrunkFactory);
2952 if (RT_SUCCESS(rc))
2953 {
2954 Assert(pTrunkIF->pIfPort);
2955 pNetwork->pTrunkIF = pTrunkIF;
2956 LogFlow(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s Network=%s\n",
2957 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
2958 return VINF_SUCCESS;
2959 }
2960 }
2961#endif /* IN_RING0 */
2962 RTSemFastMutexDestroy(pTrunkIF->FastMutex);
2963 }
2964 RTMemFree(pTrunkIF);
2965 LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
2966 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
2967 return rc;
2968}
2969
2970
2971
2972/**
2973 * Close a network which was opened/created using intnetR0OpenNetwork()/intnetR0CreateNetwork().
2974 *
2975 * @param pNetwork The network to close.
2976 * @param pSession The session handle.
2977 */
2978static int intnetR0NetworkClose(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
2979{
2980 LogFlow(("intnetR0NetworkClose: pNetwork=%p pSession=%p\n", pNetwork, pSession));
2981 AssertPtrReturn(pSession, VERR_INVALID_PARAMETER);
2982 AssertPtrReturn(pNetwork, VERR_INVALID_PARAMETER);
2983
2984 int rc = SUPR0ObjRelease(pNetwork->pvObj, pSession);
2985 LogFlow(("intnetR0NetworkClose: return %Rrc\n", rc));
2986 return rc;
2987}
2988
2989
2990/**
2991 * Object destructor callback.
2992 * This is called for reference counted objectes when the count reaches 0.
2993 *
2994 * @param pvObj The object pointer.
2995 * @param pvUser1 Pointer to the network.
2996 * @param pvUser2 Pointer to the INTNET instance data.
2997 */
2998static DECLCALLBACK(void) intnetR0NetworkDestruct(void *pvObj, void *pvUser1, void *pvUser2)
2999{
3000 PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1;
3001 PINTNET pIntNet = (PINTNET)pvUser2;
3002 Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
3003 Assert(pNetwork->pIntNet == pIntNet);
3004
3005 /* take the create/destroy sem. */
3006 RTSemFastMutexRequest(pIntNet->FastMutex);
3007
3008 /*
3009 * Deactivate the trunk connection first (if any).
3010 */
3011 if (pNetwork->pTrunkIF)
3012 intnetR0TrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */);
3013
3014 /*
3015 * Unlink the network.
3016 * Note that it needn't be in the list if we failed during creation.
3017 */
3018 PINTNETNETWORK pPrev = pIntNet->pNetworks;
3019 if (pPrev == pNetwork)
3020 pIntNet->pNetworks = pNetwork->pNext;
3021 else
3022 {
3023 for (; pPrev; pPrev = pPrev->pNext)
3024 if (pPrev->pNext == pNetwork)
3025 {
3026 pPrev->pNext = pNetwork->pNext;
3027 break;
3028 }
3029 }
3030 pNetwork->pNext = NULL;
3031 pNetwork->pvObj = NULL;
3032
3033 /*
3034 * Because of the undefined order of the per session object dereferencing when closing a session,
3035 * we have to handle the case where the network is destroyed before the interfaces. We'll
3036 * deal with this by simply orphaning the interfaces.
3037 */
3038 RTSemFastMutexRequest(pNetwork->FastMutex);
3039
3040 PINTNETIF pCur = pNetwork->pIFs;
3041 while (pCur)
3042 {
3043 PINTNETIF pNext = pCur->pNext;
3044 pCur->pNext = NULL;
3045 pCur->pNetwork = NULL;
3046 pCur = pNext;
3047 }
3048
3049 /* Grab and zap the trunk pointer before leaving the mutex. */
3050 PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;
3051 pNetwork->pTrunkIF = NULL;
3052
3053 RTSemFastMutexRelease(pNetwork->FastMutex);
3054
3055 /*
3056 * If there is a trunk, delete it.
3057 * Note that this may tak a while if we're unlucky...
3058 */
3059 if (pTrunkIF)
3060 intnetR0TrunkIfDestroy(pTrunkIF, pNetwork);
3061
3062 /*
3063 * Free resources.
3064 */
3065 RTSemFastMutexDestroy(pNetwork->FastMutex);
3066 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
3067 RTMemFree(pNetwork);
3068
3069 /* release the create/destroy sem. (can be done before trunk destruction.) */
3070 RTSemFastMutexRelease(pIntNet->FastMutex);
3071}
3072
3073
3074/**
3075 * Opens an existing network.
3076 *
3077 * @returns VBox status code.
3078 * @param pIntNet The instance data.
3079 * @param pSession The current session.
3080 * @param pszNetwork The network name. This has a valid length.
3081 * @param enmTrunkType The trunk type.
3082 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
3083 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
3084 * @param ppNetwork Where to store the pointer to the network on success.
3085 */
3086static int intnetR0OpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
3087 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
3088{
3089 LogFlow(("intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
3090 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
3091
3092 /* just pro forma validation, the caller is internal. */
3093 AssertPtr(pIntNet);
3094 AssertPtr(pSession);
3095 AssertPtr(pszNetwork);
3096 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
3097 AssertPtr(pszTrunk);
3098 Assert(!(fFlags & ~(INTNET_OPEN_FLAGS_MASK)));
3099 AssertPtr(ppNetwork);
3100 *ppNetwork = NULL;
3101
3102 /*
3103 * Search networks by name.
3104 */
3105 PINTNETNETWORK pCur;
3106 uint8_t cchName = strlen(pszNetwork);
3107 Assert(cchName && cchName < sizeof(pCur->szName)); /* caller ensures this */
3108
3109 pCur = pIntNet->pNetworks;
3110 while (pCur)
3111 {
3112 if ( pCur->cchName == cchName
3113 && !memcmp(pCur->szName, pszNetwork, cchName))
3114 {
3115 /*
3116 * Found the network, now check that we have the same ideas
3117 * about the trunk setup and security.
3118 */
3119 int rc;
3120 if ( enmTrunkType == kIntNetTrunkType_WhateverNone
3121 || ( pCur->enmTrunkType == enmTrunkType
3122 && !strcmp(pCur->szTrunk, pszTrunk)))
3123 {
3124 if (!((pCur->fFlags ^ fFlags) & INTNET_OPEN_FLAGS_SECURITY_XOR_MASK))
3125 {
3126
3127 /*
3128 * Increment the reference and check that the session
3129 * can access this network.
3130 */
3131 rc = SUPR0ObjAddRef(pCur->pvObj, pSession);
3132 if (RT_SUCCESS(rc))
3133 {
3134 if (!(pCur->fFlags & INTNET_OPEN_FLAGS_PUBLIC))
3135 rc = SUPR0ObjVerifyAccess(pCur->pvObj, pSession, pCur->szName);
3136 if (RT_SUCCESS(rc))
3137 {
3138 pCur->fFlags |= fFlags & INTNET_OPEN_FLAGS_SECURITY_OR_MASK;
3139
3140 *ppNetwork = pCur;
3141 }
3142 else
3143 SUPR0ObjRelease(pCur->pvObj, pSession);
3144 }
3145 else if (rc == VERR_WRONG_ORDER)
3146 rc = VERR_NOT_FOUND; /* destruction race, pretend the other isn't there. */
3147 }
3148 else
3149 rc = VERR_INTNET_INCOMPATIBLE_FLAGS;
3150 }
3151 else
3152 rc = VERR_INTNET_INCOMPATIBLE_TRUNK;
3153
3154 LogFlow(("intnetR0OpenNetwork: returns %Rrc *ppNetwork=%p\n", rc, *ppNetwork));
3155 return rc;
3156 }
3157 pCur = pCur->pNext;
3158 }
3159
3160 LogFlow(("intnetR0OpenNetwork: returns VERR_NOT_FOUND\n"));
3161 return VERR_NOT_FOUND;
3162}
3163
3164
3165/**
3166 * Creates a new network.
3167 *
3168 * The call must own the INTNET::FastMutex and has already attempted
3169 * opening the network and found it to be non-existing.
3170 *
3171 * @returns VBox status code.
3172 * @param pIntNet The instance data.
3173 * @param pSession The session handle.
3174 * @param pszNetwork The name of the network. This must be at least one character long and no longer
3175 * than the INTNETNETWORK::szName.
3176 * @param enmTrunkType The trunk type.
3177 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
3178 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
3179 * @param ppNetwork Where to store the network. In the case of failure whatever is returned
3180 * here should be dereferenced outside the INTNET::FastMutex.
3181 */
3182static int intnetR0CreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
3183 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
3184{
3185 LogFlow(("intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
3186 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
3187
3188 /* just pro forma validation, the caller is internal. */
3189 AssertPtr(pIntNet);
3190 AssertPtr(pSession);
3191 AssertPtr(pszNetwork);
3192 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
3193 AssertPtr(pszTrunk);
3194 Assert(!(fFlags & ~INTNET_OPEN_FLAGS_MASK));
3195 AssertPtr(ppNetwork);
3196 *ppNetwork = NULL;
3197
3198 /*
3199 * Allocate and initialize.
3200 */
3201 PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(sizeof(*pNew));
3202 if (!pNew)
3203 return VERR_NO_MEMORY;
3204 int rc = RTSemFastMutexCreate(&pNew->FastMutex);
3205 if (RT_SUCCESS(rc))
3206 {
3207 //pNew->pIFs = NULL;
3208 pNew->pIntNet = pIntNet;
3209 //pNew->cActiveIFs = 0;
3210 pNew->fFlags = fFlags;
3211 size_t cchName = strlen(pszNetwork);
3212 pNew->cchName = cchName;
3213 Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */
3214 memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */
3215 pNew->enmTrunkType = enmTrunkType;
3216 Assert(strlen(pszTrunk) < sizeof(pNew->szTrunk)); /* caller's responsibility. */
3217 strcpy(pNew->szTrunk, pszTrunk);
3218
3219 /*
3220 * Register the object in the current session and link it into the network list.
3221 */
3222 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);
3223 if (pNew->pvObj)
3224 {
3225 pNew->pNext = pIntNet->pNetworks;
3226 pIntNet->pNetworks = pNew;
3227
3228 /*
3229 * Check if the current session is actually allowed to create and open
3230 * the network. It is possible to implement network name based policies
3231 * and these must be checked now. SUPR0ObjRegister does no such checks.
3232 */
3233 rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
3234 if (RT_SUCCESS(rc))
3235 {
3236 /*
3237 * Connect the trunk.
3238 */
3239 rc = intnetR0NetworkCreateTrunkIf(pNew, pSession);
3240 if (RT_SUCCESS(rc))
3241 {
3242 *ppNetwork = pNew;
3243 LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
3244 return VINF_SUCCESS;
3245 }
3246 }
3247
3248 /*
3249 * We unlink it here so it cannot be opened when the caller leaves
3250 * INTNET::FastMutex before dereferencing it.
3251 */
3252 Assert(pIntNet->pNetworks == pNew);
3253 pIntNet->pNetworks = pNew->pNext;
3254 pNew->pNext = NULL;
3255
3256 *ppNetwork = pNew;
3257 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
3258 return rc;
3259 }
3260 rc = VERR_NO_MEMORY;
3261
3262 RTSemFastMutexDestroy(pNew->FastMutex);
3263 pNew->FastMutex = NIL_RTSEMFASTMUTEX;
3264 }
3265 RTMemFree(pNew);
3266 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
3267 return rc;
3268}
3269
3270
3271/**
3272 * Opens a network interface and connects it to the specified network.
3273 *
3274 * @returns VBox status code.
3275 * @param pIntNet The internal network instance.
3276 * @param pSession The session handle.
3277 * @param pszNetwork The network name.
3278 * @param enmTrunkType The trunk type.
3279 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
3280 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
3281 * @param fRestrictAccess Whether new participants should be subjected to access check or not.
3282 * @param cbSend The send buffer size.
3283 * @param cbRecv The receive buffer size.
3284 * @param phIf Where to store the handle to the network interface.
3285 */
3286INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork,
3287 INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
3288 unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
3289{
3290 LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
3291 pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf));
3292
3293 /*
3294 * Validate input.
3295 */
3296 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
3297
3298 AssertPtrReturn(pszNetwork, VERR_INVALID_PARAMETER);
3299 const char *pszNetworkEnd = (const char *)memchr(pszNetwork, '\0', INTNET_MAX_NETWORK_NAME);
3300 AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
3301 size_t cchNetwork = pszNetworkEnd - pszNetwork;
3302 AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
3303
3304 if (pszTrunk)
3305 {
3306 AssertPtrReturn(pszTrunk, VERR_INVALID_PARAMETER);
3307 const char *pszTrunkEnd = (const char *)memchr(pszTrunk, '\0', INTNET_MAX_TRUNK_NAME);
3308 AssertReturn(pszTrunkEnd, VERR_INVALID_PARAMETER);
3309 }
3310 else
3311 pszTrunk = "";
3312
3313 AssertMsgReturn(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End,
3314 ("%d\n", enmTrunkType), VERR_INVALID_PARAMETER);
3315 switch (enmTrunkType)
3316 {
3317 case kIntNetTrunkType_None:
3318 case kIntNetTrunkType_WhateverNone:
3319 AssertReturn(!*pszTrunk, VERR_INVALID_PARAMETER);
3320 break;
3321
3322 case kIntNetTrunkType_NetFlt:
3323 AssertReturn(pszTrunk, VERR_INVALID_PARAMETER);
3324 break;
3325
3326 default:
3327 return VERR_NOT_IMPLEMENTED;
3328 }
3329
3330 AssertMsgReturn(!(fFlags & ~INTNET_OPEN_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
3331 AssertPtrReturn(phIf, VERR_INVALID_PARAMETER);
3332
3333 /*
3334 * Acquire the mutex to serialize open/create.
3335 */
3336 int rc = RTSemFastMutexRequest(pIntNet->FastMutex);
3337 if (RT_FAILURE(rc))
3338 return rc;
3339
3340 /*
3341 * Try open / create the network and create an interface on it for the caller to use.
3342 *
3343 * Note that because of the destructors grabbing INTNET::FastMutex and us being required
3344 * to own this semaphore for the entire network opening / creation and interface creation
3345 * sequence, intnetR0CreateNetwork will have to defer the network cleanup to us on failure.
3346 */
3347 PINTNETNETWORK pNetwork = NULL;
3348 rc = intnetR0OpenNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
3349 if (RT_SUCCESS(rc) || rc == VERR_NOT_FOUND)
3350 {
3351 bool fCloseNetwork = true;
3352 if (rc == VERR_NOT_FOUND)
3353 rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
3354 if (RT_SUCCESS(rc))
3355 rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, &fCloseNetwork, phIf);
3356
3357 RTSemFastMutexRelease(pIntNet->FastMutex);
3358
3359 if (RT_FAILURE(rc) && pNetwork && fCloseNetwork)
3360 intnetR0NetworkClose(pNetwork, pSession);
3361 }
3362 else
3363 RTSemFastMutexRelease(pIntNet->FastMutex);
3364
3365 LogFlow(("INTNETR0Open: return %Rrc *phIf=%RX32\n", rc, *phIf));
3366 return rc;
3367}
3368
3369
3370/**
3371 * VMMR0 request wrapper for GMMR0MapUnmapChunk.
3372 *
3373 * @returns see GMMR0MapUnmapChunk.
3374 * @param pIntNet The internal networking instance.
3375 * @param pSession The caller's session.
3376 * @param pReq The request packet.
3377 */
3378INTNETR0DECL(int) INTNETR0OpenReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETOPENREQ pReq)
3379{
3380 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
3381 return VERR_INVALID_PARAMETER;
3382 return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->enmTrunkType, pReq->szTrunk,
3383 pReq->fFlags, pReq->cbSend, pReq->cbRecv, &pReq->hIf);
3384}
3385
3386
3387/**
3388 * Destroys an instance of the Ring-0 internal networking service.
3389 *
3390 * @param pIntNet Pointer to the instance data.
3391 */
3392INTNETR0DECL(void) INTNETR0Destroy(PINTNET pIntNet)
3393{
3394 LogFlow(("INTNETR0Destroy: pIntNet=%p\n", pIntNet));
3395
3396 /*
3397 * Allow NULL pointers.
3398 */
3399 if (!pIntNet)
3400 return;
3401 AssertPtrReturnVoid(pIntNet);
3402
3403 /*
3404 * There is not supposed to be any networks hanging around at this time.
3405 */
3406 Assert(pIntNet->pNetworks == NULL);
3407 if (pIntNet->FastMutex != NIL_RTSEMFASTMUTEX)
3408 {
3409 RTSemFastMutexDestroy(pIntNet->FastMutex);
3410 pIntNet->FastMutex = NIL_RTSEMFASTMUTEX;
3411 }
3412 if (pIntNet->hHtIfs != NIL_RTHANDLETABLE)
3413 {
3414 /** @todo does it make sense to have a deleter here? */
3415 RTHandleTableDestroy(pIntNet->hHtIfs, NULL, NULL);
3416 pIntNet->hHtIfs = NIL_RTHANDLETABLE;
3417 }
3418
3419 RTMemFree(pIntNet);
3420}
3421
3422
3423/**
3424 * Create an instance of the Ring-0 internal networking service.
3425 *
3426 * @returns VBox status code.
3427 * @param ppIntNet Where to store the instance pointer.
3428 */
3429INTNETR0DECL(int) INTNETR0Create(PINTNET *ppIntNet)
3430{
3431 LogFlow(("INTNETR0Create: ppIntNet=%p\n", ppIntNet));
3432 int rc = VERR_NO_MEMORY;
3433 PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
3434 if (pIntNet)
3435 {
3436 //pIntNet->pNetworks = NULL;
3437
3438 rc = RTSemFastMutexCreate(&pIntNet->FastMutex);
3439 if (RT_SUCCESS(rc))
3440 {
3441 rc = RTHandleTableCreateEx(&pIntNet->hHtIfs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
3442 UINT32_C(0x8ffe0000), 4096, intnetR0IfRetainHandle, NULL);
3443 if (RT_SUCCESS(rc))
3444 {
3445 *ppIntNet = pIntNet;
3446 LogFlow(("INTNETR0Create: returns VINF_SUCCESS *ppIntNet=%p\n", pIntNet));
3447 return VINF_SUCCESS;
3448 }
3449
3450 RTSemFastMutexDestroy(pIntNet->FastMutex);
3451 }
3452 RTMemFree(pIntNet);
3453 }
3454 *ppIntNet = NULL;
3455 LogFlow(("INTNETR0Create: returns %Rrc\n", rc));
3456 return rc;
3457}
3458
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