📄 cd_util.c
字号:
else
{
/*
** This should never happen. The system could be unstable,
** so log a fatal fault.
*/
GS_LogEvent( CM_INCONSISTENT_STATE, 0, psTrrbl, FATAL );
}
}
/*
** Now do the ASIC specific initialization and start up the transport.
*/
#ifdef CD_EN_OBJECTS
/* For tcpip we have to verify that messages for a given cip connection match
** the encap session that it was created on. We do that by copying the encap
** session information into the cip record.
*/
if( psConnRecord->iPort == CD_ETHERNET_PORT )
{
if( ( psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_MULTICAST )
{
if( ( psConnRecord->sEce.psMcast = en_cd_AllocMcastAddress() ) == (MCAST_P)NULL )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
goto Bailout;
}
}
if( psConnRecord->fOriginator == FALSE )
{
/*
** Save the source Sockaddr multicast or point-to-point address in the connection
** and transport record "sEce". This is so the T->O tag can be returned with
** the FWD_OPEN_REPLY, and so UDP Class1 packets will have the correct Sockaddr for
** the "sendto".
*/
en_cd_SaveSendToAddress( psConnRecord );
}
pTr->sEce = psTrrbl->psConnRecord->sEce;
} /* End if an ethernet port */
#endif
eStatus = (CD_s[ psConnRecord->iPort ].StartTransport)( pTr );
if( eStatus != SUCCESS )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
goto Bailout;
}
} /* end if start */
#ifdef CD_EN_OBJECTS
/*
** The transport was already reserved, we need to add the address to the message
** going back so the client can listen in on an existing connections
*/
else if (( psTrrbl->eRequest == TREQ_START_TRANSPORTS ) &&
( psConnRecord->iPort == CD_ETHERNET_PORT ) )
{
if( psConnRecord->fOriginator == FALSE ||
(psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_POINT )
{
/*
** Save the source Sockaddr multicast or point-to-point address in the connection
** and transport record "sEce". This is so the T->O tag can be returned with
** the FWD_OPEN_REPLY, and so UDP Class1 packets will have the correct Sockaddr for
** the "sendto".
*/
psConnRecord->sEce.psMcast = pTr->sEce.psMcast;
en_cd_SaveSendToAddress( psConnRecord );
}
}
#endif
/*
** start edits: October,5th 2005, H.F.
**
** If a Producer Connection Point is already in use, it shall
** adjust its API timer according to the new requested I/O connection, if
** this needs a lesser API. This will avoid a timeout for the new I/O
** connection.
*/
/*
** check, if the Producer Connection Point uses at least the
** requested API; if not...
*/
if( ( psTrrbl->eRequest == TREQ_START_TRANSPORTS )
&& ( pTr->iState & CD_TS_STARTED )
&& ( pTr->lProApi > psConnRecord->lProApi ) )
{
/* ...apply new (faster) APIs */
pTr->lProApi = pTr->lConApi = psConnRecord->lProApi;
pTr->lProInhib = psConnRecord->lProInhib;
/* adjust the API timer */
pTr->xAPITimer->nRetrigger = pTr->lProApi/1000;
/* retrigger API timer */
GS_RetriggerTimer(pTr->xAPITimer);
en_cd_Class1TxPacket( pTr->pBufA, pTr);
/*
** start edits: October,13th 2005, H.F.:
**
** update data after transmission
** (NOTE: An ad_ResyncCommAndAppBufs() call before executing
** en_cd_Class1TxPacket() does not work!)
*/
GS_PutMsgQueueBits( AD_xQid, AD_BIT_MSG_SENT_PRO );
/*
** end edits: October,13th 2005, H.F.
*/
}
/*
** end edits: October,5th 2005, H.F.
*/
} /* end if Class 1 - reserve a producer transport */
/*
**-------------------------------------------------------------
** Reserve a consumer transport for this connection record
**-------------------------------------------------------------
*/
/*
** Allocate a transport, if not yet done
*/
if( psConnRecord->iConTransportId == 0 )
{
if( ( eStatus = cd_AllocateTransport( psTrrbl, FALSE ) ) != SUCCESS )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_NO_BUFFER;
goto Bailout;
}
}
/*
** TODO: For Ethernet, this check for multicast transport already in use is NOT functional.
*/
pTr = cd_LookupTransportRecord( psConnRecord->iPort, psConnRecord->iConTransportId );
if( pTr == NULL )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_NO_BUFFER;
goto Bailout;
}
/*
** Link the connection serial number to the transport record.
** Error out if too many multicast connections.
*/
bNumLinked = cd_LinkConnSnToTransport( psConnRecord->iConnectionSn, pTr, psConnRecord->iPort );
if( bNumLinked < 0 )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_NO_BUFFER;
goto Bailout;
}
/*
** If reserve has not been done or if only one connection record
** is linked to the transport, do the reserve.
**
** Note that a second pass is allowed here in case we need to pick
** up information that has changed in the connection record.
** (e.g. connection ID's that were returned in a FO request)
*/
if( ( ( pTr->iState & CD_TS_RESERVED ) == 0 )
|| ( bNumLinked == 1 ) )
{
pTr->iState |= CD_TS_RESERVED;
/*
** Save the transport type.
*/
pTr->bTransportType = psConnRecord->bConTransportType;
/*
** Fill in any tags that we select
** with our mac id and the transport number.
*/
if( ( psConnRecord->iConConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_POINT )
{
/*
** Ethernet uses the module incarnation count for the upper half of
** the 32 bit connection ID
*/
/*
** jjw note change of using the transport record transport id rather
** than the connection record transport ID. The connection record id
** does not have the radioactive bits, the transport id does.
*/
if( psConnRecord->iPort == CD_ETHERNET_PORT )
{
lConnId = pTr->iTransportId |
( ( UINT32 ) sRadioActiveMasks.nIncarnation << 16 );
}
else if( psConnRecord->iPort == CD_CONTROLNET_PORT )
{
lConnId = pTr->iTransportId |
( ( UINT32 ) CD_s[ CD_CONTROLNET_PORT ].bMacId << 16 );
}
psConnRecord->lLeConConnId = UC_lTOlLe( lConnId );
}
else
{
lConnId = UC_lLeTOl( psConnRecord->lLeConConnId );
/*
** MCast connection, so reserve space
*/
if( psTrrbl->eRequest == TREQ_RESERVE_TRANSPORTS )
{
if ( ( psConnRecord->sEce.psMcast = ( MCAST_P ) GS_Malloc( sizeof( MCAST ) ) ) == (MCAST_P)NULL )
{
eStatus = CD_TRANSPORT_ALLOC_FAIL;
psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
goto Bailout;
}
/*
** Set mcast addr to 0, so if we free it before it is set up,
** we don't erroneously think it is a valid mcast addr.
*/
psConnRecord->sEce.psMcast->sMc_addr.sin_addr.s_addr = 0;
}
}
/*
** Copy the Mac Id and Transport Id from the Conn Id
*/
if ( psConnRecord->iPort == CD_ETHERNET_PORT )
{
/*
** Use 4 byte connection record
*/
*( UINT32 * ) &pTr->abRxTag[0] = UC_lLeTOl( psConnRecord->lLeConConnId );
}
else
{
pTr->abRxTag[ 0 ] = ( UINT8 ) (lConnId >> 16);
pTr->abRxTag[ 1 ] = ( UINT8 ) lConnId;
pTr->abRxTag[ 2 ] = ( UINT8 ) (lConnId >> 8);
}
if( iClass == CM_TCT_CLASS_1 )
{
/*
** Since we are in the consumer section we can't be a producer
*/
pTr->fServerConsumer = TRUE;
}
if( iClass == CM_TCT_CLASS_3 )
{
/*
** Class 3.
*/
/*
** Fill in producer tag (if we select it)
** with our mac id and the Consumer transport id number.
** Else, use what was provided in the connection record.
*/
if( ( psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_MULTICAST )
{
#ifdef CD_EN_OBJECTS
/*
** Ethernet uses the module incarnation count for the upper half of
** the 32 bit connection ID
*/
if (psConnRecord->iPort == CD_ETHERNET_PORT)
lConnId = psConnRecord->iConTransportId |
( ( UINT32 ) sRadioActiveMasks.nIncarnation << 16 );
else
#endif
lConnId = psConnRecord->iConTransportId |
( ( UINT32 ) CD_s[ psConnRecord->iPort ].bMacId << 16 );
psConnRecord->lLeProConnId = UC_lTOlLe( lConnId );
}
else
{
lConnId = UC_lLeTOl( psConnRecord->lLeProConnId );
}
/*
** Copy the Mac Id and Transport Id from the Conn Id
*/
if ( psConnRecord->iPort == CD_ETHERNET_PORT )
{
/*
** Use 4 byte connection record
*/
*( UINT32 * ) &pTr->abTxTag[0] = UC_lLeTOl( psConnRecord->lLeProConnId );
}
else
{
pTr->abTxTag[ 0 ] = ( UINT8 ) (lConnId >> 16);
pTr->abTxTag[ 1 ] = ( UINT8 ) lConnId;
pTr->abTxTag[ 2 ] = ( UINT8 ) (lConnId >> 8);
}
/*
** Use the generic consumer transport that uses the ring queue.
*/
pTr->fServerConsumer = psConnRecord->bClassTrigger & CM_TCT_CLIENTSERVER_MASK;
/*
** If Client and not bridged,
** Create the client retry timer.
*/
if( !pTr->fServerConsumer && !pTr->fBridged )
{
/*
** Build the timeout tribble.
**
** But first, check to see if it is already done.
*/
if( pTr->pRetryTot == NULL )
{
pTr->pRetryTot = GS_NewTrrbl( CD_TimeoutTrrblType );
pTr->pRetryTot->eRequest = TREQ_CLASS3_CLIENT_TIMEOUT;
pTr->pRetryTot->iId = psConnRecord->iConTransportId;
pTr->pRetryTot->iPort = psTrrbl->psConnRecord->iPort;
/*
** Now build the timer itself.
*/
pTr->xRetryTimer = GS_NewLinkedMsgTimer( TIMER_ONE_SHOT,
psConnRecord->lConApi / 1000L,
psConnRecord->lConApi / 1000L,
CD_s[ psTrrbl->psConnRecord->iPort ].xTxUnschedHiQid,
pTr->pRetryTot );
if( pTr->xRetryTimer == NULL )
{
GS_Free( pTr->pRetryTot );
eStatus = CD_RESOURCE_UNAVAILABLE;
psConnRecord->iERC = CM_ERC_NO_BUFFER;
goto Bailout;
}
} /* end if pTr->pRetryTot */
} /* end if client */
} /* end if Class 3 */
if( iClass == CM_TCT_CLASS_1 )
{
/*
** If this is and explicit transport reserve request, put information
** into the connection record that may be used latter during the
** start phase of transport comissioning.
**
** For example, if this is a class 1 bridged connection, a copy
** function could be placed into the connection record at this time
** and later, during the strart phase, retrived and used,
** by the other transport on the other side of the bridge.
*/
if( psTrrbl->eRequest == TREQ_RESERVE_TRANSPORTS )
{
/* For Consumer Transport */
switch( psConnRecord->bConTransportType & CD_XPORT_TYPE_MASK )
{
case CD_XPORT_TYPE_PROVIDE_FUNCTION:
/*
** Provide a copy function that will be called whenever new
** data is ready to be Consumed. That is, the transport
** stores the data until the application needs to consume it.
**
** This case is valid for the NetLinx Dualport, which should
** have it's own transport commission function.
** It is not valid for either ControlNet ASIC, so flag an error.
*/
eStatus = CD_UNSUPPORTED_TRANSPORT;
psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
goto Bailout;
case CD_XPORT_TYPE_DEFAULT:
case CD_XPORT_TYPE_CALL_FUNCTION:
/*
** This case is how the Consumer Xports have worked in the past.
**
** Do nothing here. Wait for start of transport to get pointer
** to function to call.
*/
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -