Files
m241Neelima/components/ip_net2-6.9/vxbridge/src/mirrorEnd.c
T
2026-07-30 11:19:44 +05:30

1108 lines
30 KiB
C

/* mirrorEnd.c - mirroring END device driver */
/*
* Copyright (c) 2000-2006 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01x,13jan06,xhs Support simnet, defect WIND00397421.
01w,12feb09,ggz Change paths to bridge.h, mirrorEnd.h header files
01v,27nov07,tlu Add support to set/update interface RUNNING/NOT RUNNING state
01u,25oct06,kch Fixed warnings.
01t,15aug06,tlu Ported to IPNET
01s,04feb06,kch Fixed apigen doc errors and warnings.
01r,15apr05,svk Update API descriptions
01q,07feb05,svk Remove unused/obsolete include
01p,19jul04,myz removed end_err_block_flag and moved muxTxRestart to bridge.
01o,07aug03,myz zero out drvCtrl at init, call mirrorEndStop and undo last fix
in mirrorEndUnload
01n,03jun03,myz clear the snarfCount in mirrorEndUnload
01m,22may03,svk Add a missing cast, debug message changes
01l,06may03,svk Remove the costly netJobAdd in mirrorEndSend()
01k,02may03,svk Add multicast support, avoid a possible deadlock,
address optimzation, re-format for coding convention
01j,17apr03,svk Update copyright date
01i,22nov02,zhu removed compiler warnings
01h,22nov02,zhu added polling mode support
01g,18oct02,ep removing gnu warning
01f,15apr02,zhu changed arg types to call mirrorEndReceive
01e,15apr02,zhu made changes to docs
01d,10apr02,svk Replace another netJobAdd with mirrorEndReceive
01c,09apr02,svk Replace a netJobAdd with mirrorEndReceive
01b,27sep01,zhu TSR#257133 flow control
01a,10oct00,jhl created
*/
/*
DESCRIPTION
This library implements a mirroring END device driver.
INCLUDE FILES: mirrorEnd.h
SEE ALSO: endLib
*/
/* includes */
#include <ipcom_sock.h>
#include <etherMultiLib.h>
#include <netLib.h>
#include <stdio.h>
#include <string.h>
/* Uncomment the line below to enable debug messages */
/*#define END_MIRROR_DEBUG */
#ifdef END_MIRROR_DEBUG
int endMirrorDebug = 1;
#define LOG_MSG \
if (endMirrorDebug) \
printf
#else
#define LOG_MSG(a0,a1,a2,a3,a4,a5,a6)
#endif
#undef END_MACROS
#include "endLib.h"
#include "endMedia.h"
#include "lstLib.h"
#include "netBufLib.h"
#include "bridge.h"
#include "mirrorEnd.h"
/* defines */
#define LENGTH_MIN_FBUF 9 /* min. size of the first buffer in a frame */
#define SPEED 10000000/* ethernet speed */
#define MAX_MIRROR_CHANNELS 2
#define CHANNEL_DOWN 0
#define CHANNEL_UP 1
/* macros */
/* A shortcut for getting the hardware address from the MIB II stuff. */
#define END_HADDR(pEnd) ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
#define END_HADDR_LEN(pEnd) ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
/* both pMac1 and pMac2 must point to a two byte boundary */
#define MAC_ADDR_EQ(pMac1,pMac2) \
( (pMac1[0] == pMac2[0]) && \
(pMac1[1] == pMac2[1]) && \
(pMac1[2] == pMac2[2]) )
/* pMacAddr must point to a two byte boundary */
#define IS_BROADCAST(pMacAddr) \
( (pMacAddr[0] == bcastMacAddr[0]) && \
(pMacAddr[1] == bcastMacAddr[1]) && \
(pMacAddr[2] == bcastMacAddr[2]) )
/* typedefs */
/* END control structure */
typedef struct end_ctrl
{
END_OBJ endObject; /* base class */
int unit; /* unit number */
BOOL promiscuous; /* promiscuous on or off */
BOOL polling; /* polling mode */
END_OBJ * pPhyEnd;
UINT16 enetAddr[3]; /* ethernet address of this entry */
} END_CTRL;
/* globals */
int mirrorSendStatus = OK;
extern LIST bridgePortList;
/* locals */
LOCAL UINT16 bcastMacAddr[3] = { 0xFFFF, 0xFFFF, 0xFFFF };
LOCAL END_CTRL drvCtrl[MAX_MIRROR_CHANNELS]; /* array of driver control */
LOCAL int channelState[MAX_MIRROR_CHANNELS] = {CHANNEL_DOWN, CHANNEL_DOWN };
/* prototypes */
END_OBJ* mirrorEndLoad(char* initString);
LOCAL STATUS mirrorEndStart(END_CTRL* pDrvCtrl);
LOCAL STATUS mirrorEndStop(END_CTRL* pDrvCtrl);
LOCAL STATUS mirrorEndUnload(END_CTRL* pDrvCtrl);
LOCAL int mirrorEndIoctl(END_CTRL* pDrvCtrl, int cmd, caddr_t data);
LOCAL STATUS mirrorEndSend(END_CTRL* pDrvCtrl, M_BLK* pMblk);
LOCAL void mirrorEndReceive(END_CTRL* pDrvCtrl, M_BLK* pMblk);
LOCAL STATUS mirrorEndMCastAddrAdd(END_CTRL* pDrvCtrl, char* pAddress);
LOCAL STATUS mirrorEndMCastAddrDel(END_CTRL* pDrvCtrl, char* pAddress);
LOCAL STATUS mirrorEndMCastAddrGet(END_CTRL* pDrvCtrl, MULTI_TABLE* pTable);
LOCAL STATUS mirrorEndPollStart(END_CTRL* pDrvCtrl);
LOCAL STATUS mirrorEndPollStop(END_CTRL* pDrvCtrl);
LOCAL STATUS mirrorEndPollSend(END_CTRL* pDrvCtrl, M_BLK* pMblk);
LOCAL STATUS mirrorEndPollReceive(END_CTRL* pDrvCtrl, M_BLK* pMblk);
LOCAL BOOL isInMulticastList(END_CTRL* pDrvCtrl, UINT16* enetAddr);
extern STATUS bridgeNextPhyDevEndGet(char *,int *);
/*
* Define the device function table. This is static across all driver
* instances.
*/
LOCAL NET_FUNCS netFuncs =
{
(FUNCPTR)mirrorEndStart, /* start func. */
(FUNCPTR)mirrorEndStop, /* stop func. */
(FUNCPTR)mirrorEndUnload, /* unload func. */
(FUNCPTR)mirrorEndIoctl, /* ioctl func. */
(FUNCPTR)mirrorEndSend, /* send func. */
(FUNCPTR)mirrorEndMCastAddrAdd, /* multicast add func. */
(FUNCPTR)mirrorEndMCastAddrDel, /* multicast delete func. */
(FUNCPTR)mirrorEndMCastAddrGet, /* multicast get fun. */
(FUNCPTR)mirrorEndPollSend, /* polling send func. */
(FUNCPTR)mirrorEndPollReceive, /* polling receive func. */
endEtherAddressForm, /* Put address info into a packet. */
endEtherPacketDataGet, /* Get a pointer to packet data. */
endEtherPacketAddrGet /* Get packet addresses. */
};
/*******************************************************************************
* mirrorEndLoad - initialize the driver and device
*
* This routine initializes the driver and the device. All of the
* device-specific parameters are passed in the <initString> parameter.
* <initstring> is of the following format, where <unit> is the device
* driver unit number:
*
* <unit>:
*
* Mirror driver unit number can be 'MIRROR_STACK_UNIT_NUM' (0) or
* 'MIRROR_BRIDGE_UNIT_NUM' (1). These are defined in:
*
* target/h/wrn/bridge/mirrorEnd.h
*
* Typically, unit 0 is attached to the network stack and unit 1 is attached to
* the bridge.
*
* RETURNS: An END object pointer on success, or NULL on error
*
* ERRNO: N/A
*
*/
END_OBJ* mirrorEndLoad
(
char* initString
)
{
END_CTRL* pDrvCtrl;
if (initString == NULL)
return NULL;
if (initString[0] == 0)
{
bcopy((char *)MIRROR_DEV_NAME, initString, MIRROR_DEV_NAME_LEN);
return NULL;
}
/* Parse InitString */
switch (initString[0])
{
case '0':
pDrvCtrl = &drvCtrl[0];
bzero((char *)pDrvCtrl,sizeof(END_CTRL));
pDrvCtrl->unit = 0;
SYS_ENET_ADDR_GET((char *) pDrvCtrl->enetAddr);
break;
case '1':
pDrvCtrl = &drvCtrl[1];
bzero((char *)pDrvCtrl,sizeof(END_CTRL));
pDrvCtrl->unit = 1;
/* if unit ever REALLY needs a MAC address, change this appropriately */
SYS_ENET_ADDR_GET((char *) pDrvCtrl->enetAddr);
break;
default:
return NULL;
}
/* Check if we are already attached */
if (pDrvCtrl->endObject.attached == TRUE)
return &pDrvCtrl->endObject;
/* endObject initializations */
if (END_OBJ_INIT(&pDrvCtrl->endObject,
(void*)pDrvCtrl,
MIRROR_DEV_NAME,
pDrvCtrl->unit,
&netFuncs,
MIRROR_END_OBJ_STRING) == ERROR)
{
return NULL;
}
/* Initialize MIB2 entries */
if (END_MIB_INIT(&pDrvCtrl->endObject,
M2_ifType_ethernet_csmacd,
(UCHAR *) pDrvCtrl->enetAddr,
6,
ETHERMTU,
SPEED) == ERROR)
{
return NULL;
}
/* we need to import the memory pool from a real physical driver. At least
* the WDB end driver is using it
*/
if (pDrvCtrl->unit == 0)
{
char devName[END_NAME_MAX];
int unit = 0;
bzero(devName,END_NAME_MAX);
if (bridgeNextPhyDevEndGet(devName,&unit) == ERROR)
{
printf("mirrorEndLoad: No physical device found\n");
}
else
{
END_OBJ * pEnd;
pEnd = endFindByName(devName,unit);
if (pEnd != NULL)
pDrvCtrl->endObject.pNetPool = pEnd->pNetPool;
pDrvCtrl->pPhyEnd = pEnd;
}
}
/* Mark the device ready */
/* IFF_SCAT is not defined by default */
/*
END_OBJ_READY(&pDrvCtrl->endObject,
IFF_NOTRAILERS | IP_IFF_BROADCAST | IFF_MULTICAST);
*/
END_OBJ_READY(&pDrvCtrl->endObject,
IP_IFF_BROADCAST | IP_IFF_MULTICAST);
/* Successful return */
return &pDrvCtrl->endObject;
}
/*******************************************************************************
* mirrorEndStart - start the device
*
* This routine marks the interface as up.
*
* The complement of this routine is mirrorEndStop(). Once a unit is reset by
* mirrorEndStop(), it may be re-initialized to a running state by this routine.
*
* RETURNS: OK if successful, otherwise ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndStart
(
END_CTRL* pDrvCtrl
)
{
/* initialize flag(s) */
pDrvCtrl->polling = FALSE;
pDrvCtrl->promiscuous = FALSE;
/* mark the channel state as "UP" */
channelState[pDrvCtrl->unit] = CHANNEL_UP;
/* raise the interface flags - mark the device as up */
END_FLAGS_SET (&pDrvCtrl->endObject, IP_IFF_UP | IP_IFF_RUNNING);
/* update the interface flags */
mirrorEndRunningState();
return OK;
}
/*******************************************************************************
* mirrorEndStop - stop the device
*
* This routine marks the interface as down.
*
* The complement of this routine is mirrorEndStart(). Once a unit is
* stop in this routine, it may be re-initialized to a running state by
* mirrorEndStart().
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndStop
(
END_CTRL* pDrvCtrl
)
{
/* mark the channel state as "DOWN" */
channelState[pDrvCtrl->unit] = CHANNEL_DOWN;
/* mark the driver as down */
END_FLAGS_CLR (&pDrvCtrl->endObject, IP_IFF_UP | IP_IFF_RUNNING);
return OK;
}
/******************************************************************************
* mirrorEndUnload - unload a driver from the system
*
* This function first brings down the device, and then frees any
* stuff that was allocated by the driver in the load function.
*
* RETURNS: OK always
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndUnload
(
END_CTRL* pDrvCtrl
)
{
mirrorEndStop(pDrvCtrl);
END_OBJECT_UNLOAD(&pDrvCtrl->endObject);
return OK;
}
/*******************************************************************************
* mirrorEndIoctl - network interface control routine
*
* This routine implements the network interface control functions.
* It handles EIOCSIFADDR, EIOCGADDR, EIOCSFLAGS, EIOCGFLAGS,
* EIOCPOLLSTART, EIOCPOLLSTOP, EIOCGMIB2 and EIOCGFBUF ENDERRBLOCK commands.
*
* RETURNS: OK if successful, otherwise EINVAL
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL int mirrorEndIoctl
(
END_CTRL* pDrvCtrl,
int cmd,
caddr_t data
)
{
int error = 0;
INT32 value;
END_OBJ* pEndObj = &pDrvCtrl->endObject;
END_MEDIA * pMedia;
switch (cmd)
{
case EIOCSADDR:
if (data == NULL)
{
error = EINVAL;
}
else
{
bcopy((char*)data,
(char*)END_HADDR(pEndObj),
END_HADDR_LEN(pEndObj));
}
break;
case EIOCGADDR:
if (data == NULL)
{
error = EINVAL;
}
else
{
bcopy((char*)END_HADDR(pEndObj),
(char*)data,
END_HADDR_LEN(pEndObj));
}
break;
case EIOCSFLAGS:
value = (INT32)((ULONG) data & 0xFFFFFFFF);
if (value < 0)
{
value = -value;
value--;
END_FLAGS_CLR(pEndObj, value);
}
else
{
END_FLAGS_SET(pEndObj, value);
}
if (END_FLAGS_GET(pEndObj) & IP_IFF_PROMISC)
{
pDrvCtrl->promiscuous = TRUE;
}
else
{
pDrvCtrl->promiscuous = FALSE;
}
break;
case EIOCGFLAGS:
if (data == NULL)
{
error = EINVAL;
}
else
{
*(int*)data = END_FLAGS_GET(pEndObj);
}
break;
case EIOCGIFMEDIA:
if (data == NULL)
error = EINVAL;
else
{
value = END_FLAGS_GET(pEndObj);
pMedia = (END_MEDIA *)data;
pMedia->endMediaActive = IFM_AVALID;
pMedia->endMediaStatus = IFM_AVALID;
if (value & IP_IFF_RUNNING)
{
LOG_MSG("ioctl with EIOCGIFMEDIA, set active bit \n",
1, 2, 3, 4, 5, 6);
pMedia->endMediaStatus |= IFM_ACTIVE;
}
else
{
LOG_MSG("ioctl with EIOCGIFMEDIA, clear active bit \n",
1, 2, 3, 4, 5, 6);
pMedia->endMediaStatus &= ~IFM_ACTIVE;
}
}
break;
case EIOCPOLLSTART:
error = mirrorEndPollStart(pDrvCtrl);
break;
case EIOCPOLLSTOP:
error = mirrorEndPollStop(pDrvCtrl);
break;
case EIOCGMIB2:
if (data == NULL)
{
error = EINVAL;
}
else
{
bcopy((char*)&pDrvCtrl->endObject.mib2Tbl,
(char*)data,
sizeof(pDrvCtrl->endObject.mib2Tbl));
}
break;
case EIOCGFBUF:
if (data == NULL)
{
error = EINVAL;
}
else
{
*(int*)data = LENGTH_MIN_FBUF;
}
break;
default:
error = EINVAL;
break;
}
return error;
}
/******************************************************************************
* mirrorEndRunningState - update the driver running state
*
* This function gets the state from all bridge's underlying END devices, then
* update the bridge's RUNNING state accordingly. If all underlying devices
* are inactive, the bridge interface is marked inactive, and its RUNNING bit
* is cleared. As long as one underlying device is active, the bridge interface
* will be marked as active, and its RUNNING bit is set.
*
* RETURNS: OK always
*
* ERRNO: N/A
*
* NOMANUAL
*/
STATUS mirrorEndRunningState(void)
{
BRIDGE_PORT_INFO* pPortInfo;
END_OBJ *pEnd0, *pEnd1;
END_MEDIA media;
long flags;
pEnd1 = endFindByName (MIRROR_DEV_NAME,MIRROR_STACK_UNIT_NUM);
pEnd0 = endFindByName (MIRROR_DEV_NAME,MIRROR_BRIDGE_UNIT_NUM);
if (pEnd1)
flags = END_FLAGS_GET(pEnd1);
else
return OK;
for (pPortInfo = (BRIDGE_PORT_INFO*)lstFirst(&bridgePortList);
(pPortInfo != NULL) && (strcmp(pPortInfo->name, MIRROR_DEV_NAME)!=0);
pPortInfo = (BRIDGE_PORT_INFO*)lstNext((NODE*)pPortInfo))
{
int rc = muxIoctl(pPortInfo->pMuxBindCookie,EIOCGIFMEDIA,(char *)&media);
if(rc != OK) {
LOG_MSG("mirrorEndRunningState: Error:%d when trying the get media status for %s%d\n",
rc, pPortInfo->name, pPortInfo->unitNum, 4, 5, 6);
} else {
LOG_MSG("mirrorEndRunningState: port %s, unit %d, status 0x%x\n",
pPortInfo->name, pPortInfo->unitNum,
media.endMediaStatus, 4, 5, 6);
}
/*
* If the device supports EIOCGIFMEDIA, trust it if it says
* that the link is down. Otherwise, assume the link is up.
*/
if (rc != OK || (media.endMediaStatus & (IFM_AVALID|IFM_ACTIVE)) ==
(IFM_AVALID|IFM_ACTIVE))
{
if ((flags & IP_IFF_RUNNING) == 0)
{
LOG_MSG("mirrorEndRunningState: state changed to RUNNING\n",
1, 2, 3, 4, 5, 6);
/* raise both interface flags - mark the devices as RUNNING */
if (pEnd0) END_FLAGS_SET (pEnd0, IP_IFF_RUNNING);
END_FLAGS_SET (pEnd1, IP_IFF_RUNNING);
/* inform the stack about the interface UP state change */
jobQueueStdPost (netJobQueueId, NET_TASK_QJOB_PRI,
muxLinkUpNotify, pEnd1,
NULL, NULL, NULL, NULL);
}
return OK;
}
}
if (flags & IP_IFF_RUNNING)
{
LOG_MSG("mirrorEndRunningState: state changed to NOT RUNNING\n",
1, 2, 3, 4, 5, 6);
/* mark both drivers as NOT RUNNING */
if (pEnd0) END_FLAGS_CLR (pEnd0, IP_IFF_RUNNING);
END_FLAGS_CLR (pEnd1, IP_IFF_RUNNING);
/* inform the stack about the interface UP state change */
jobQueueStdPost (netJobQueueId, NET_TASK_QJOB_PRI,
muxLinkDownNotify, pEnd1,
NULL, NULL, NULL, NULL);
}
return OK;
}
/*******************************************************************************
* mirrorEndSend - output packet to network interface device
*
* This routine() takes a M_BLK* and sends off the data in the M_BLK*.
* The buffer must already have the addressing information properly installed
* in it. This is done by a higher layer.
*
* muxSend() calls this routine each time it wants to send a packet.
*
* RETURNS: OK , ERROR or END_ERR_BLOCK
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndSend
(
END_CTRL* pDrvCtrl,
M_BLK* pMblk
)
{
int otherHalfOfMirror;
int status = OK;
LOG_MSG("mirrorEndSend: unit: %d, pollMode: %d, ",
(int)pDrvCtrl->unit,
(int)pDrvCtrl->polling,
4, 5, 6, 7);
LOG_MSG("dst:%02X:%02X:%02X:%02X:%02X:%02X, ",
*(UCHAR *)(pMblk->mBlkHdr.mData),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 1),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 2),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 3),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 4),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 5));
LOG_MSG("src:%02X:%02X:%02X:%02X:%02X:%02X\n",
*((UCHAR *)(pMblk->mBlkHdr.mData) + 6),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 7),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 8),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 9),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 10),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 11));
if (pDrvCtrl->polling == TRUE)
{
netMblkClChainFree (pMblk); /* free the given mBlk chain */
return ERROR;
}
otherHalfOfMirror = pDrvCtrl->unit ^ 1; /* 0->1, 1->0 */
if (channelState[otherHalfOfMirror] == CHANNEL_UP)
{
/* other half of mirror is up, send packet there */
if (pDrvCtrl->unit == MIRROR_STACK_UNIT_NUM)
mirrorSendStatus = OK;
/*
* In the previous version of the Bridge, calling mirrorEndReceive
* directly caused deadlock when bridge tries to flood multicasts
* outgoing from local stack. One way to avoid the deadlock is to
* call mirrorEndReceive from tNetTask by using netJobAdd. But this
* causes performance hit, and also overloads the netJob ring buffer.
*
* The better solution is to call mirrorEndReceive directly, and
* avoid deadlock by not taking the bridge port list semaphore when
* flooding packets to all bridge ports. Taking this semaphore was
* previously thought necessary to guard against removal of a bridge
* port when the bridge is flooding packets to that port. The
* possibility of this occurring is very small, and can be avoided
* if the user makes sure the bridge port is free of incoming and
* outgoing traffic before removing the bridge port.
*/
mirrorEndReceive(&drvCtrl[otherHalfOfMirror], pMblk);
if (pDrvCtrl->unit == MIRROR_STACK_UNIT_NUM)
status = mirrorSendStatus;
}
else
{
/* other half of mirror is not up, toss the packet */
netMblkClChainFree(pMblk);
}
/* Bump the statistic counter. */
END_ERR_ADD(&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);
return status;
}
/*******************************************************************************
* isInMulticastList - is the address is a multicast address for this device?
*
* This routine checks whether the given address matches a multicast address
* from the current list of multicast addresses.
*
* RETURNS: TRUE or FALSE
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL BOOL isInMulticastList
(
END_CTRL* pDrvCtrl, /* pointer to END_CTRL structure */
UINT16* enetAddr /* address to check */
)
{
ETHER_MULTI* pCurr;
pCurr = (ETHER_MULTI *)lstFirst(&pDrvCtrl->endObject.multiList);
while (pCurr != (ETHER_MULTI *)NULL)
{
if (((ULONG)(pCurr->addr) & 0x01) == 0)
{
/* address is aligned on a 2 or 4 byte boundary */
if (MAC_ADDR_EQ(((UINT16 *)(pCurr->addr)), enetAddr) == TRUE)
return TRUE;
}
else
{
/* address is aligned on a byte-boundary */
if (bcmp(pCurr->addr, (char *)enetAddr, 6) == 0)
return TRUE;
}
pCurr = (ETHER_MULTI *)lstNext(&pCurr->node);
}
return FALSE;
}
/*******************************************************************************
* mirrorEndReceive - process an input frame
*
* This routine processes an input frame, then passes it up to the higher
* level in a form it expects. Buffer loaning, promiscuous mode are all
* supported. Trailer protocols is not supported.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL void mirrorEndReceive
(
END_CTRL* pDrvCtrl, /* pointer to END_CTRL structure */
M_BLK* pMblk
)
{
UINT16 * pTmp;
UINT16 enetAddr[3];
LOG_MSG("mirrorEndReceive: unit: %d, ",
(int)pDrvCtrl->unit,
2, 3, 4, 5, 6);
LOG_MSG("dst:%02X:%02X:%02X:%02X:%02X:%02X, ",
*(UCHAR *)(pMblk->mBlkHdr.mData),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 1),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 2),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 3),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 4),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 5));
LOG_MSG("src:%02X:%02X:%02X:%02X:%02X:%02X\n",
*((UCHAR *)(pMblk->mBlkHdr.mData) + 6),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 7),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 8),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 9),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 10),
*((UCHAR *)(pMblk->mBlkHdr.mData) + 11));
/* don't allow the packet through if in polling mode */
if (pDrvCtrl->polling == TRUE)
{
netMblkClChainFree(pMblk);
return;
}
/* if unit is not in promiscuous mode, filter packets to receive only
* packets for our MAC address or broadcasts.
*/
if (pDrvCtrl->promiscuous == FALSE)
{
pTmp = (UINT16 *)(pMblk->mBlkHdr.mData);
if (((ULONG)(pTmp) & 0x01) == 0)
{
/* address is aligned on a 2 or 4 byte boundary */
enetAddr[0] = pTmp[0];
enetAddr[1] = pTmp[1];
enetAddr[2] = pTmp[2];
}
else
{
/* address is aligned on a byte-boundary */
bcopy((char *)pTmp, (char *)enetAddr, 6);
}
if ((MAC_ADDR_EQ(enetAddr, pDrvCtrl->enetAddr) == 0) &&
(IS_BROADCAST(enetAddr) == 0) &&
(isInMulticastList(pDrvCtrl, enetAddr) == FALSE))
{
LOG_MSG("Dest addr not my addr/broadcast/multicast - dropping!\n",
1, 2, 3, 4, 5, 6);
netMblkClChainFree(pMblk);
return;
}
}
LOG_MSG("Sending up the packet to my network stack\n",
1, 2, 3, 4, 5, 6);
/* send up to protocol */
END_RCV_RTN_CALL(&pDrvCtrl->endObject, pMblk);
/* bump input packet counter */
END_ERR_ADD(&pDrvCtrl->endObject, MIB2_IN_UCAST, +1);
}
/*******************************************************************************
* mirrorEndMCastAddrAdd - add a multicast address for the device
*
* Multicast makes no sense in this driver. Keep the table for "get" calls.
*
* RETURNS : OK or ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndMCastAddrAdd
(
END_CTRL* pDrvCtrl,
char* pAddr
)
{
STATUS error;
error = etherMultiAdd(&pDrvCtrl->endObject.multiList, pAddr);
if (error == ENETRESET)
{
pDrvCtrl->endObject.nMulti++;
error = OK;
}
return (error == OK) ? OK : ERROR;
}
/*******************************************************************************
* mirrorEndMCastAddrDel - delete a multicast address for the device
*
* This routine deletes a multicast address from the current list of
* multicast addresses.
*
* RETURNS : OK or ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndMCastAddrDel
(
END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */
char * pAddr /* Address to delete from the table. */
)
{
STATUS error;
error = etherMultiDel(&pDrvCtrl->endObject.multiList, pAddr);
if (error == ENETRESET)
{
pDrvCtrl->endObject.nMulti--;
error = OK;
}
return (error == OK) ? OK : ERROR;
}
/*******************************************************************************
* mirrorEndMCastAddrGet - get the current multicast address list
*
* This routine returns the current multicast address list in <pTable>
*
* RETURNS: Multicast address list or NULL
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndMCastAddrGet
(
END_CTRL* pDrvCtrl,
MULTI_TABLE* pTable
)
{
return etherMultiGet(&pDrvCtrl->endObject.multiList, pTable);
}
/*******************************************************************************
* mirrorEndPollStart - start polling mode
*
* Using polled mode for the mirror driver makes no sense. Do not use it.
*
* RETURNS: OK
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndPollStart
(
END_CTRL* pDrvCtrl
)
{
/* Set the polling flag */
pDrvCtrl->polling = TRUE;
/* need to set the real device, we either put all devices associated with
* this vritual mirror device into poll mode, or simply put one
* currently only put one.
*/
(*pDrvCtrl->pPhyEnd->pFuncTable->ioctl)(pDrvCtrl->pPhyEnd,EIOCPOLLSTART,0);
return OK;
}
/*******************************************************************************
* mirrorEndPollStop - stop polling mode
*
* This routine stops the mirrorEnd from the polling mode.
*
* RETURNS: OK always
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndPollStop
(
END_CTRL* pDrvCtrl
)
{
/* reset the polling flag */
pDrvCtrl->polling = FALSE;
(*pDrvCtrl->pPhyEnd->pFuncTable->ioctl)(pDrvCtrl->pPhyEnd,EIOCPOLLSTOP,0);
return OK;
}
/******************************************************************************
* mirrorEndPollSend - transmit a packet in polled mode
*
* This routine is called by a user to try and send a packet on the
* device. It sends a packet directly on the network from the caller without
* going through the normal processes of queuing a packet on an output queue
* and the waiting for the device to decide to transmit it.
*
* If it detects a transmission error, the restart command is issued.
*
* These routine should not call any kernel functions.
*
* RETURNS: OK or EAGAIN
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndPollSend
(
END_CTRL* pDrvCtrl,
M_BLK* pMblk
)
{
STATUS status;
/* mirror 1 should not call this function */
if (pDrvCtrl->unit != 0)
return ERROR;
/* call the poll routine in the real device */
status = pDrvCtrl->pPhyEnd->pFuncTable->pollSend(pDrvCtrl->pPhyEnd,
pMblk);
/* Bump the statistic counter. */
END_ERR_ADD(&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);
return status;
}
/*******************************************************************************
* mirrorEndPollReceive - receive a packet in polled mode
*
* This routine receives a packet in polled mode
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS mirrorEndPollReceive
(
END_CTRL* pDrvCtrl,
M_BLK* pMblk
)
{
return pDrvCtrl->pPhyEnd->pFuncTable->pollRcv(pDrvCtrl->pPhyEnd,
pMblk);
}