📄 endlib.c
字号:
* through <pSrcAddr> and <pDstAddr> mBlks and returns an M_BLK_ID to the* assembled link level header. If the <bcastFlag> argument is TRUE, it* sets the destination address to the link-level broadcast address and* ignores the <pDstAddr> contents. This routine prepends the link level header* into <pMblk> if there is enough space available or it allocates a new* mBlk/clBlk/cluster and prepends the new mBlk to the mBlk chain passed in* <pMblk>. This routine returns a pointer to an mBlk which contains the* link level header information.** RETURNS: M_BLK_ID or NULL.** NOMANUAL*/M_BLK_ID end8023AddressForm ( M_BLK_ID pMblk, M_BLK_ID pSrcAddr, M_BLK_ID pDstAddr, BOOL bcastFlag ) { short dataLen; /* length of data including LLC */ USHORT *pSrc; USHORT *pDst; struct llc * pLlc; /* link layer control header */ dataLen = pMblk->mBlkPktHdr.len + LLC_SNAP_FRAMELEN; dataLen = htons (dataLen); M_PREPEND(pMblk, SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN, M_DONTWAIT); if (pMblk != NULL) { /* Fill in destination address */ pDst = (USHORT *)pMblk->m_data; if (bcastFlag) { pDst[0] = 0xFFFF; pDst[1] = 0xFFFF; pDst[2] = 0xFFFF; } else { pSrc = (USHORT *)pDstAddr->m_data; pDst[0] = pSrc[0]; pDst[1] = pSrc[1]; pDst[2] = pSrc[2]; } /* Fill in source address */ pDst += 3; pSrc = (USHORT *)pSrcAddr->m_data; pDst[0] = pSrc[0]; pDst[1] = pSrc[1]; pDst[2] = pSrc[2]; /* Fill in length */ pDst += 3; pDst[0] = dataLen; /* Fill in LLC using SNAP values */ pDst++; pLlc = (struct llc *) pDst; pLlc->llc_dsap = LLC_SNAP_LSAP; pLlc->llc_ssap = LLC_SNAP_LSAP; pLlc->llc_un.type_snap.control = LLC_UI; pLlc->llc_un.type_snap.org_code[0] = pLlc->llc_un.type_snap.org_code[1] = pLlc->llc_un.type_snap.org_code[2] = 0; /* Enter ethernet network type code into the LLC snap field */ pLlc->llc_un.type_snap.ether_type = pDstAddr->mBlkHdr.reserved; } return (pMblk); }/******************************************************************************** endEtherAddressForm - form an Ethernet address into a packet** This routine accepts the source and destination addressing information * through <pSrcAddr> and <pDstAddr> and returns an 'M_BLK_ID' that points * to the assembled link-level header. To do this, this routine prepends * the link-level header into the cluster associated with <pMblk> if there * is enough space available in the cluster. It then returns a pointer to * the pointer referenced in <pMblk>. However, if there is not enough space * in the cluster associated with <pMblk>, this routine reserves a * new 'mBlk'-'clBlk'-cluster construct for the header information. * It then prepends the new 'mBlk' to the 'mBlk' passed in <pMblk>. As the * function value, this routine then returns a pointer to the new 'mBlk', * which the head of a chain of 'mBlk' structures. The second element of this * chain is the 'mBlk' referenced in <pMblk>. ** RETURNS: M_BLK_ID or NULL.*/M_BLK_ID endEtherAddressForm ( M_BLK_ID pMblk, /* pointer to packet mBlk */ M_BLK_ID pSrcAddr, /* pointer to source address */ M_BLK_ID pDstAddr, /* pointer to destination address */ BOOL bcastFlag /* use link-level broadcast? */ ) { USHORT *pDst; USHORT *pSrc; M_PREPEND(pMblk, SIZEOF_ETHERHEADER, M_DONTWAIT); /* * This routine has been optimized somewhat in order to avoid * the use of bcopy(). On some architectures, a bcopy() could * result in a call into (allegedly) optimized architecture- * specific routines. This may be fine for copying large chunks * of data, but we're only copying 6 bytes. It's simpler just * to open code some 16-bit assignments. The compiler would be * hard-pressed to produce sub-optimal code for this, and it * avoids at least one function call (possibly several). */ if (pMblk != NULL) { pDst = (USHORT *)pMblk->m_data; if (bcastFlag) { pDst[0] = 0xFFFF; pDst[1] = 0xFFFF; pDst[2] = 0xFFFF; } else { pSrc = (USHORT *)pDstAddr->m_data; pDst[0] = pSrc[0]; pDst[1] = pSrc[1]; pDst[2] = pSrc[2]; } /* Advance to the source address field, fill it in. */ pDst += 3; pSrc = (USHORT *)pSrcAddr->m_data; pDst[0] = pSrc[0]; pDst[1] = pSrc[1]; pDst[2] = pSrc[2]; ((struct ether_header *)pMblk->m_data)->ether_type = pDstAddr->mBlkHdr.reserved; } return (pMblk); }/******************************************************************************** endEtherPacketDataGet - return the beginning of the packet data** This routine fills the given <pLinkHdrInfo> with the appropriate offsets.** RETURNS: OK or ERROR.*/STATUS endEtherPacketDataGet ( M_BLK_ID pMblk, LL_HDR_INFO * pLinkHdrInfo ) { struct ether_header * pEnetHdr; struct ether_header enetHdr; struct llc * pLLCHdr; struct llc llcHdr; USHORT etherType; pLinkHdrInfo->destAddrOffset = 0; pLinkHdrInfo->destSize = 6; pLinkHdrInfo->srcAddrOffset = 6; pLinkHdrInfo->srcSize = 6; /* Try for RFC 894 first as it's the most common. */ /* * make sure entire ether_header is in first M_BLK * if not then copy the data to a temporary buffer */ if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER) { pEnetHdr = &enetHdr; if (netMblkOffsetToBufCopy (pMblk, 0, (char *) pEnetHdr, SIZEOF_ETHERHEADER, (FUNCPTR) bcopy) < SIZEOF_ETHERHEADER) { return (ERROR); } } else pEnetHdr = (struct ether_header *)pMblk->mBlkHdr.mData; etherType = ntohs(pEnetHdr->ether_type); /* Deal with 802.3 addressing. */ /* Here is the algorithm. */ /* If the etherType is less than the MTU then we know that */ /* this is an 802.x address from RFC 1700. */ if (etherType <= ETHERMTU) { /* * make sure entire ether_header + llc_hdr is in first M_BLK * if not then copy the data to a temporary buffer */ if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN) { pLLCHdr = &llcHdr; if (netMblkOffsetToBufCopy (pMblk, SIZEOF_ETHERHEADER, (char *) pLLCHdr, LLC_SNAP_FRAMELEN, (FUNCPTR) bcopy) < LLC_SNAP_FRAMELEN) { return (ERROR); } } else pLLCHdr = (struct llc *)((char *)pEnetHdr + SIZEOF_ETHERHEADER); /* Now it may be IP over 802.x so we check to see if the */ /* destination SAP is IP, if so we snag the ethertype from the */ /* proper place. */ /* Now if it's NOT IP over 802.x then we just used the DSAP as */ /* the etherType. */ if (pLLCHdr->llc_dsap == LLC_SNAP_LSAP) { etherType = ntohs(pLLCHdr->llc_un.type_snap.ether_type); pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 8; } else { /* no SNAP header */ pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 3; etherType = pLLCHdr->llc_dsap; } } else { pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER; } pLinkHdrInfo->pktType = etherType; return (OK); }/******************************************************************************** endEtherPacketAddrGet - locate the addresses in a packet** This routine takes a 'M_BLK_ID', locates the address information, and * adjusts the M_BLK_ID structures referenced in <pSrc>, <pDst>, <pESrc>, * and <pEDst> so that their pData members point to the addressing * information in the packet. The addressing information is not copied. * All 'mBlk' structures share the same cluster.** RETURNS: OK or ERROR.*/STATUS endEtherPacketAddrGet ( M_BLK_ID pMblk, /* pointer to packet */ M_BLK_ID pSrc, /* pointer to local source address */ M_BLK_ID pDst, /* pointer to local destination address */ M_BLK_ID pESrc, /* pointer to remote source address (if any) */ M_BLK_ID pEDst /* pointer to remote destination address (if any) */ ) { if (pSrc != NULL) { pSrc = netMblkDup (pMblk, pSrc); pSrc->mBlkHdr.mData += 6; pSrc->mBlkHdr.mLen = 6; } if (pDst != NULL) { pDst = netMblkDup (pMblk, pDst); pDst->mBlkHdr.mLen = 6; } if (pESrc != NULL) { pESrc = netMblkDup (pMblk, pESrc); pESrc->mBlkHdr.mData += 6; pESrc->mBlkHdr.mLen = 6; } if (pEDst != NULL) { pEDst = netMblkDup (pMblk, pEDst); pEDst->mBlkHdr.mLen = 6; } return (OK); }/*************************************************************************** * * endPollStatsPoll - poll an interface's information * * This routine calls the endPollStatsIfPoll() routine to gather * information from a particular interface, then re-arms the interface's * polling watchdog timer. * * NOMANUAL * * RETURNS: N/A * */LOCAL void endPollStatsPoll ( END_IFDRVCONF *pDrvConf ) { if (pDrvConf == NULL) return; /* Gather the stats */ pDrvConf->ifPollRtn (pDrvConf); /* Reload the watchdog. */ wdStart(pDrvConf->ifWatchdog, pDrvConf->ifPollInterval, (FUNCPTR) endPollStatsJobQueue, (int) (pDrvConf)); return; }/*************************************************************************** * * endPollStatsJobQueue - polling stats counter scheduler routine * * This routine is an intermediary function necessitated by the fact * that wdStart() only takes two arguments: we need to pass it three * (netJobAdd(), plus two others). This routine just invokes netJobAdd() * to call the endPollStatsIfPoll() routine and passes it a pointer to * the END_IFDRVCONF structure being polled. We must use netJobAdd() * here to avoid executing the rest of the polling code at interrupt * context. * * NOMANUAL * * RETURNS: N/A * */LOCAL void endPollStatsJobQueue ( END_IFDRVCONF *pDrvConf ) { netJobAdd ((FUNCPTR) endPollStatsPoll, (int) pDrvConf, 0, 0, 0, 0); return; }/******************************************************************************** endPollStatsInit - initialize polling statistics updates** This routine is used to begin polling of the interface specified by* pCookie and will periodically call out to the pIfPollRtn function, which* will collect the interface statistics. If the driver supports polling* updates, this routine will start a watchdog that will invoke the* pIfPollRtn routine periodically. The watchdog will automatically* re-arm itself. The pIfPollRtn will be passed a pointer to the driver's* END_IFDRVCONF structure as an argument.** RETURNS: ERROR if the driver doesn't support polling, otherwise OK.*/STATUS endPollStatsInit ( void * pCookie, FUNCPTR pIfPollRtn ) { END_IFDRVCONF * pDrvConf; int error; /* Sanity check */ if (pCookie == NULL || pIfPollRtn == NULL) return (ERROR); /* Get this driver's configuration info */ error = muxIoctl (pCookie, EIOCGPOLLCONF, (caddr_t) &pDrvConf); /* Return error if driver doesn't support stats polling. */ if (error) return (error); /* Create the watchdog. */ pDrvConf->ifWatchdog = wdCreate (); if (pDrvConf->ifWatchdog == NULL) return (ERROR); pDrvConf->ifEndObj = NULL; pDrvConf->ifMuxCookie = pCookie; pDrvConf->ifPollRtn = pIfPollRtn; /* Kick off the watchdog. */ wdStart (pDrvConf->ifWatchdog, pDrvConf->ifPollInterval, (FUNCPTR) endPollStatsJobQueue, (int) (pDrvConf)); return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -