VirtualBox

Changeset 28332 in vbox


Ignore:
Timestamp:
Apr 14, 2010 9:52:52 PM (15 years ago)
Author:
vboxsync
Message:

DrvIntNet: ring-0 experimentation and fixes.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/pdmnetifs.h

    r28320 r28332  
    353353/** PDMINETWORKUP interface ID. */
    354354#define PDMINETWORKUP_IID                       "67e7e7a8-2594-4649-a1e3-7cee680c6083"
     355/** PDMINETWORKUP interface method names. */
     356#define PDMINETWORKUP_SYM_LIST                  "BeginXmit;AllocBuf;FreeBuf;SendBuf;EndXmit;SetPromiscuousMode"
    355357
    356358
  • trunk/src/VBox/Devices/Makefile.kmk

    r28290 r28332  
    568568        Network/DevPCNet.cpp \
    569569        Serial/DevSerial.cpp \
    570         Parallel/DevParallel.cpp \
    571         \
    572         Network/DrvIntNet.cpp
     570        Parallel/DevParallel.cpp
    573571
    574572 ifdef VBOX_DYNAMIC_NET_ATTACH
  • trunk/src/VBox/Devices/Network/DevE1000.cpp

    r28328 r28332  
    37533753    if (pDrv)
    37543754    {
    3755         rc = pDrv->pfnBeginXmit(pDrv, true /*fOnWorkerThread*/);
     3755        rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
    37563756        if (RT_FAILURE(rc))
    37573757            return rc;
  • trunk/src/VBox/Devices/Network/DrvIntNet.cpp

    r28328 r28332  
    4949#include "../Builtins.h"
    5050
     51// To play with R0 drivers.
     52//#define VBOX_WITH_DRVINTNET_IN_R0
     53
    5154
    5255/*******************************************************************************
     
    5659 * The state of the asynchronous thread.
    5760 */
    58 typedef enum ASYNCSTATE
     61typedef enum RECVSTATE
    5962{
    6063    /** The thread is suspended. */
    61     ASYNCSTATE_SUSPENDED = 1,
     64    RECVSTATE_SUSPENDED = 1,
    6265    /** The thread is running. */
    63     ASYNCSTATE_RUNNING,
     66    RECVSTATE_RUNNING,
    6467    /** The thread must (/has) terminate. */
    65     ASYNCSTATE_TERMINATE,
     68    RECVSTATE_TERMINATE,
    6669    /** The usual 32-bit type blowup. */
    67     ASYNCSTATE_32BIT_HACK = 0x7fffffff
    68 } ASYNCSTATE;
     70    RECVSTATE_32BIT_HACK = 0x7fffffff
     71} RECVSTATE;
    6972
    7073/**
     
    108111    /** Interface handle. */
    109112    INTNETIFHANDLE                  hIf;
    110     /** The thread state. */
    111     ASYNCSTATE volatile             enmState;
     113    /** The receive thread state. */
     114    RECVSTATE volatile             enmRecvState;
    112115    /** The receive thread. */
    113116    RTTHREAD                        hRecvThread;
     
    219222}
    220223
     224#endif /* IN_RING3 */
    221225
    222226/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
     
    225229 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
    226230 */
    227 static DECLCALLBACK(int) drvR3IntNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
    228 {
    229     PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
    230 #if 1
     231PDMBOTHCBDECL(int) drvIntNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
     232{
     233    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
     234#if !defined(IN_RING3)
     235    int rc = VERR_SEM_BUSY;
     236    Assert(!fOnWorkerThread);
     237#elif 1
    231238    int rc = PDMCritSectTryEnter(&pThis->XmitLock);
    232239#else
     
    246253         *        forth?  I seriously think this is ring-0 only... */
    247254        if (    !fOnWorkerThread
    248             &&  !ASMAtomicUoReadBool(&pThis->fXmitOnXmitThread)
    249             &&  ASMAtomicCmpXchgBool(&pThis->fXmitSignalled, true, false))
     255            /*&&  !ASMAtomicUoReadBool(&pThis->fXmitOnXmitThread)
     256            &&  ASMAtomicCmpXchgBool(&pThis->fXmitSignalled, true, false)*/)
    250257        {
    251258            rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
     
    261268 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
    262269 */
    263 static DECLCALLBACK(int) drvR3IntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
    264                                                 PCPDMNETWORKGSO pGso,  PPPDMSCATTERGATHER ppSgBuf)
    265 {
    266     PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     270PDMBOTHCBDECL(int) drvIntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
     271                                                   PCPDMNETWORKGSO pGso,  PPPDMSCATTERGATHER ppSgBuf)
     272{
     273    PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
    267274    int         rc    = VINF_SUCCESS;
    268275    Assert(cbMin < UINT32_MAX / 2);
    269276    Assert(PDMCritSectIsOwner(&pThis->XmitLock));
    270277
     278#ifdef IN_RING3
    271279    /*
    272280     * Allocate a S/G buffer.
     
    330338    /** @todo implement VERR_TRY_AGAIN  */
    331339    return rc;
     340
     341#else   /* !IN_RING3 */
     342    rc = VERR_TRY_AGAIN;
     343    return rc;
     344#endif  /* !IN_RING3 */
    332345}
    333346
     
    336349 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
    337350 */
    338 static DECLCALLBACK(int) drvR3IntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
    339 {
    340     PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     351PDMBOTHCBDECL(int) drvIntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
     352{
     353    PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
    341354    PINTNETHDR  pHdr  = (PINTNETHDR)pSgBuf->pvAllocator;
    342355    Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
     
    346359    Assert(PDMCritSectIsOwner(&pThis->XmitLock));
    347360
     361#ifdef IN_RING3
    348362    /** @todo LATER: try unalloc the frame. */
    349363    pHdr->u16Type = INTNETHDR_TYPE_PADDING;
     
    352366    RTMemCacheFree(pThis->hSgCache, pSgBuf);
    353367    return VINF_SUCCESS;
     368#else
     369    return VERR_INTERNAL_ERROR_5;
     370#endif
    354371}
    355372
     
    358375 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
    359376 */
    360 static DECLCALLBACK(int) drvR3IntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
    361 {
    362     PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     377PDMBOTHCBDECL(int) drvIntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
     378{
     379    PDRVINTNET  pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
    363380    STAM_PROFILE_START(&pThis->StatTransmit, a);
    364381
     
    371388        STAM_COUNTER_INC(&pThis->StatSentGso);
    372389
     390#ifdef IN_RING3
    373391    /*
    374392     * Commit the frame and push it thru the switch.
     
    388406    STAM_PROFILE_STOP(&pThis->StatTransmit, a);
    389407    return VINF_SUCCESS;
     408#else
     409    return VERR_INTERNAL_ERROR_4;
     410#endif
    390411}
    391412
     
    394415 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
    395416 */
    396 static DECLCALLBACK(void) drvR3IntNetUp_EndXmit(PPDMINETWORKUP pInterface)
    397 {
    398     PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     417PDMBOTHCBDECL(void) drvIntNetUp_EndXmit(PPDMINETWORKUP pInterface)
     418{
     419    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
    399420    ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, false);
    400421    PDMCritSectLeave(&pThis->XmitLock);
     
    405426 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
    406427 */
    407 static DECLCALLBACK(void) drvR3IntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
    408 {
    409     PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     428PDMBOTHCBDECL(void) drvIntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
     429{
     430    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
     431#ifdef IN_RING3
    410432    INTNETIFSETPROMISCUOUSMODEREQ Req;
    411433    Req.Hdr.u32Magic    = SUPVMMR0REQHDR_MAGIC;
     
    415437    Req.fPromiscuous    = fPromiscuous;
    416438    int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
    417     LogFlow(("drvR3IntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
     439    LogFlow(("drvIntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
    418440    AssertRC(rc);
    419 }
    420 
     441#else
     442    /** @todo  */
     443    AssertFailed();
     444#endif
     445}
     446
     447#ifdef IN_RING3
    421448
    422449/**
     
    425452static DECLCALLBACK(void) drvR3IntNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
    426453{
    427     PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
     454    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
    428455    bool fLinkDown;
    429456    switch (enmLinkState)
     
    539566             * Check the state and then inspect the packet.
    540567             */
    541             if (pThis->enmState != ASYNCSTATE_RUNNING)
     568            if (pThis->enmRecvState != RECVSTATE_RUNNING)
    542569            {
    543570                STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
     
    675702         * Wait for data, checking the state before we block.
    676703         */
    677         if (pThis->enmState != ASYNCSTATE_RUNNING)
     704        if (pThis->enmRecvState != RECVSTATE_RUNNING)
    678705        {
    679706            STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
     
    719746    for (;;)
    720747    {
    721         ASYNCSTATE enmState = pThis->enmState;
    722         switch (enmState)
     748        RECVSTATE enmRecvState = pThis->enmRecvState;
     749        switch (enmRecvState)
    723750        {
    724             case ASYNCSTATE_SUSPENDED:
     751            case RECVSTATE_SUSPENDED:
    725752            {
    726753                int rc = RTSemEventWait(pThis->hRecvEvt, 30000);
     
    734761            }
    735762
    736             case ASYNCSTATE_RUNNING:
     763            case RECVSTATE_RUNNING:
    737764            {
    738765                int rc = drvR3IntNetRecvRun(pThis);
     
    747774
    748775            default:
    749                 AssertMsgFailed(("Invalid state %d\n", enmState));
    750             case ASYNCSTATE_TERMINATE:
     776                AssertMsgFailed(("Invalid state %d\n", enmRecvState));
     777            case RECVSTATE_TERMINATE:
    751778                LogFlow(("drvR3IntNetRecvThread: returns VINF_SUCCESS\n"));
    752779                return VINF_SUCCESS;
     
    765792    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseRC);
    766793
    767 #ifdef VBOX_WITH_R0_AND_RC_DRIVERS
     794#if 0
    768795    PDMIBASERC_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpRC);
    769796#endif
     
    780807{
    781808    PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseR0);
    782 #ifdef VBOX_WITH_R0_AND_RC_DRIVERS
     809#ifdef VBOX_WITH_DRVINTNET_IN_R0
    783810    PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpR0);
    784811#endif
     
    818845    if (!pThis->fActivateEarlyDeactivateLate)
    819846    {
    820         ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
     847        ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
    821848        drvR3IntNetSetActive(pThis, false /* fActive */);
    822849    }
     
    872899    if (!pThis->fActivateEarlyDeactivateLate)
    873900    {
    874         ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
     901        ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
    875902        RTSemEventSignal(pThis->hRecvEvt);
    876903        drvR3IntNetUpdateMacAddress(pThis); /* (could be a state restore) */
     
    917944    if (!pThis->fActivateEarlyDeactivateLate)
    918945    {
    919         ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
     946        ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
    920947        drvR3IntNetSetActive(pThis, false /* fActive */);
    921948    }
     
    934961    if (!pThis->fActivateEarlyDeactivateLate)
    935962    {
    936         ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
     963        ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
    937964        RTSemEventSignal(pThis->hRecvEvt);
    938965        drvR3IntNetUpdateMacAddress(pThis);
     
    968995     * Indicate to the thread that it's time to quit.
    969996     */
    970     ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
     997    ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_TERMINATE);
    971998    ASMAtomicXchgSize(&pThis->fLinkDown, true);
    972999    RTSEMEVENT hRecvEvt = pThis->hRecvEvt;
     
    9911018     * Wait for the thread to terminate.
    9921019     */
     1020    if (hRecvEvt != NIL_RTSEMEVENT)
     1021        RTSemEventSignal(hRecvEvt);
     1022
     1023    if (pThis->pXmitThread)
     1024    {
     1025        int rc = PDMR3ThreadDestroy(pThis->pXmitThread, NULL);
     1026        AssertRC(rc);
     1027        pThis->pXmitThread = NULL;
     1028    }
     1029
    9931030    if (pThis->hRecvThread != NIL_RTTHREAD)
    9941031    {
    995         if (hRecvEvt != NIL_RTSEMEVENT)
    996             RTSemEventSignal(hRecvEvt);
    9971032        int rc = RTThreadWait(pThis->hRecvThread, 5000, NULL);
    9981033        AssertRC(rc);
     
    10001035    }
    10011036
    1002     /*
    1003      * Destroy the semaphore, S/G cache and xmit lock.
     1037
     1038    /*
     1039     * Destroy the semaphores, S/G cache and xmit lock.
    10041040     */
    10051041    if (hRecvEvt != NIL_RTSEMEVENT)
    10061042        RTSemEventDestroy(hRecvEvt);
     1043
     1044    if (pThis->hXmitEvt != NIL_SUPSEMEVENT)
     1045    {
     1046        SUPSemEventClose(pThis->pSupDrvSession, pThis->hXmitEvt);
     1047        pThis->hXmitEvt = NIL_SUPSEMEVENT;
     1048    }
    10071049
    10081050    RTMemCacheDestroy(pThis->hSgCache);
     
    10591101    pThis->pSupDrvSession                           = PDMDrvHlpGetSupDrvSession(pDrvIns);
    10601102    pThis->hSgCache                                 = NIL_RTMEMCACHE;
    1061     pThis->enmState                                 = ASYNCSTATE_SUSPENDED;
     1103    pThis->enmRecvState                             = RECVSTATE_SUSPENDED;
    10621104    pThis->fActivateEarlyDeactivateLate             = false;
    10631105    /* IBase* */
     
    10661108    pThis->IBaseRC.pfnQueryInterface                = drvR3IntNetIBaseRC_QueryInterface;
    10671109    /* INetworkUp */
    1068     pThis->INetworkUpR3.pfnBeginXmit                = drvR3IntNetUp_BeginXmit;
    1069     pThis->INetworkUpR3.pfnAllocBuf                 = drvR3IntNetUp_AllocBuf;
    1070     pThis->INetworkUpR3.pfnFreeBuf                  = drvR3IntNetUp_FreeBuf;
    1071     pThis->INetworkUpR3.pfnSendBuf                  = drvR3IntNetUp_SendBuf;
    1072     pThis->INetworkUpR3.pfnEndXmit                  = drvR3IntNetUp_EndXmit;
    1073     pThis->INetworkUpR3.pfnSetPromiscuousMode       = drvR3IntNetUp_SetPromiscuousMode;
     1110    pThis->INetworkUpR3.pfnBeginXmit                = drvIntNetUp_BeginXmit;
     1111    pThis->INetworkUpR3.pfnAllocBuf                 = drvIntNetUp_AllocBuf;
     1112    pThis->INetworkUpR3.pfnFreeBuf                  = drvIntNetUp_FreeBuf;
     1113    pThis->INetworkUpR3.pfnSendBuf                  = drvIntNetUp_SendBuf;
     1114    pThis->INetworkUpR3.pfnEndXmit                  = drvIntNetUp_EndXmit;
     1115    pThis->INetworkUpR3.pfnSetPromiscuousMode       = drvIntNetUp_SetPromiscuousMode;
    10741116    pThis->INetworkUpR3.pfnNotifyLinkChanged        = drvR3IntNetUp_NotifyLinkChanged;
    10751117
     
    13781420
    13791421    /*
    1380      * Create the async I/O threads.
    1381      * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
    1382      */
    1383     rc = RTThreadCreate(&pThis->hRecvThread, drvR3IntNetRecvThread, pThis, 0,
    1384                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET-RECV");
    1385     if (RT_FAILURE(rc))
    1386     {
    1387         AssertRC(rc);
    1388         return rc;
    1389     }
    1390 
    1391     rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hXmitEvt);
    1392     AssertRCReturn(rc, rc);
    1393 
    1394     rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pXmitThread, pThis,
    1395                                drvR3IntNetXmitThread, drvR3IntNetXmitWakeUp, 0, RTTHREADTYPE_IO, "INTNET-XMIT");
    1396     AssertRCReturn(rc, rc);
    1397 
    1398     /*
    13991422     * Register statistics.
    14001423     */
     
    14181441
    14191442    /*
     1443     * Create the async I/O threads.
     1444     * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
     1445     */
     1446    rc = RTThreadCreate(&pThis->hRecvThread, drvR3IntNetRecvThread, pThis, 0,
     1447                        RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET-RECV");
     1448    if (RT_FAILURE(rc))
     1449    {
     1450        AssertRC(rc);
     1451        return rc;
     1452    }
     1453
     1454    rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hXmitEvt);
     1455    AssertRCReturn(rc, rc);
     1456
     1457    rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pXmitThread, pThis,
     1458                               drvR3IntNetXmitThread, drvR3IntNetXmitWakeUp, 0, RTTHREADTYPE_IO, "INTNET-XMIT");
     1459    AssertRCReturn(rc, rc);
     1460
     1461#ifdef VBOX_WITH_DRVINTNET_IN_R0
     1462    /*
     1463     * Resolve the ring-0 context interface addresses.
     1464     */
     1465    rc = pDrvIns->pHlpR3->pfnLdrGetR0InterfaceSymbols(pDrvIns, &pThis->INetworkUpR0, sizeof(pThis->INetworkUpR0),
     1466                                                      "drvIntNetUp_", PDMINETWORKUP_SYM_LIST);
     1467    AssertLogRelRCReturn(rc, rc);
     1468#endif
     1469
     1470    /*
    14201471     * Activate data transmission as early as possible
    14211472     */
    14221473    if (pThis->fActivateEarlyDeactivateLate)
    14231474    {
    1424         ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
     1475        ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
    14251476        RTSemEventSignal(pThis->hRecvEvt);
    14261477
     
    14291480    }
    14301481
    1431    return rc;
     1482    return rc;
    14321483}
    14331484
     
    14441495    "IntNet",
    14451496    /* szRCMod */
    1446     "VBoxDDRC",
     1497    "VBoxDDGC.rc",
    14471498    /* szR0Mod */
    1448     "VBoxDDR0",
     1499    "VBoxDDR0.r0",
    14491500    /* pszDescription */
    14501501    "Internal Networking Transport Driver",
    14511502    /* fFlags */
    1452 #ifdef VBOX_WITH_R0_AND_RC_DRIVERS
    1453     PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC,
     1503#ifdef VBOX_WITH_DRVINTNET_IN_R0
     1504    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
    14541505#else
    14551506    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
Note: See TracChangeset for help on using the changeset viewer.

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