📄 if_enp.c
字号:
return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* enpOutput - the driver's output routine** The destination address is passed to this function as a pointer to a* generic socket address structure. This address information is first* converted to the six byte destination address and type field that we* need to build a proper Ethernet frame.** The data to be sent out is held in a chain of mbufs. This function is* passed a pointer to the head mbuf. The data in each mbuf fragment must* be copied to the device's packet buffer.*/LOCAL STATUS enpOutput ( IDR *pIDR, MBUF *pMbuf, SOCK *pDest ) { int lostCarrier; int blen; u_short packetType; u_char *bufStart; DRV_CTRL *pDrvCtrl; ENPDEVICE *pDev; MBUF *pTempMbuf; BCB *pBCB; u_char *pBuf; char destEnetAddr [6];#ifdef ENP_DEBUG printf ( "enp: output: pIDR=%x, pMbuf=%x, pDest=%x\n", pIDR, pMbuf, pDest );#endif /* Check ifnet flags. Return error if incorrect. */ if ( (pIDR->ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING) ) return (ENETDOWN); /* Attempt to convert socket addr into enet addr and packet type. * Note that if ARP resolution of the address is required, the ARP * module will call our routine again to transmit the ARP request * packet. This means we may actually call ourselves recursively! */ if (convertDestAddr (pIDR,pDest, destEnetAddr, &packetType, pMbuf) == FALSE) return (OK); /* I KNOW returning OK is stupid, but it is correct */ /* Get driver control pointer */ pDrvCtrl = & drvCtrl [pIDR->ac_if.if_unit]; pDev = (ENPDEVICE *) pDrvCtrl->enpAddr; /* Obtain exclusive access to transmitter. This is necessary because * certain events can cause netTask to run a job that attempts to transmit * a packet. We can only allow one task here at a time. */ semTake (pDrvCtrl->TxSem, WAIT_FOREVER); /* some boards (eg. iv3201a,hkv2f,mv133) get bus errors with 32bit access */ READLONG (&pDev->enp_stat.e_lost_carrier, &lostCarrier); lostCarrier = ntohl (lostCarrier); if (lostCarrier > pDrvCtrl->lostCarrier) { /* The test should probably be "not equal", however, roll-over * will take a long time. After reset pDrvCtrl->lostCarrier won't * be in sync -- we should initialize (i.e. read) it elsewhere. * * Keep a separate count of lost carrier so statics don't * get messed up. */ pDrvCtrl->lostCarrier = lostCarrier;#ifdef ENP_DEBUG logMsg ("enp%d: lost carrier\n", pDrvCtrl->idr.ac_if.if_unit, 0, 0, 0, 0, 0);#endif } /* If no resource available, discard packet */ if (enpringempty ((RING *) &pDev->enp_hostfree)) { semGive (pDrvCtrl->TxSem); /* Release exclusive access. */ m_freem (pMbuf); return (OK); } pBCB = (BCB *) enpringget ((RING *)&pDev->enp_hostfree); /* Get pointer to buffer to fill with outgoing packet */ READLONG ((&pBCB->b_addr), &bufStart); bufStart = (u_char *) ntohl ((int)bufStart); /* First fill in the Ethernet header */ pBuf = bufStart; bcopyBytes (destEnetAddr, (char *) pBuf, 6); pBuf += 6; bcopyBytes ((char *) pDrvCtrl->idr.ac_enaddr, (char *) pBuf, 6); pBuf += 6; bcopyBytes ( (char *)&packetType, (char *) pBuf, 2); pBuf += 2; /* copy data from mbufs to enp a word at a time. * most other netif drivers use copy_from_mbufs() to accomplish * this task. we're doing this manually here because we * need to take care of a special case (hkv2f + ENP, see below). */ pTempMbuf = pMbuf; /* copy ptr */ while (pTempMbuf != NULL) { /* if destination adrs starts at odd byte boundary * copy a byte at a time. copying a word from hkv2f into ENP memory * starting at an odd byte causes problems. */ if (((int) pBuf & 1) == 1) bcopyBytes ( mtod (pTempMbuf, char *), (char *) pBuf, (int) pTempMbuf->m_len ); else { blen = pTempMbuf->m_len >> 1; /* copy 2 bytes at a time */ bcopyWords (mtod (pTempMbuf, char *), (char *) pBuf, blen); /* copy the remaining byte if any */ blen <<= 1; if (blen != pTempMbuf->m_len) { *((char *) (pBuf + blen)) = *((char *) (mtod (pTempMbuf, char *) + blen)); } } /* Move pointer ahead, and get next mbuf pointer */ pBuf += pTempMbuf->m_len; pTempMbuf = pTempMbuf->m_next; } /* Done with mbufs, release them to system */ m_freem (pMbuf); /* Set length of packet */ blen = max ( MINPKTSIZE, ((int) pBuf - (int) bufStart) ); pBCB->b_len = htons (blen); /* Put the BCB on the outgoing ring, and if this is the only entry on * the ring, generate an interrupt to the ENP by writing to the special * location in the shared memory space. Some boards require this * interrupt, while others work fine without it, and still others perform * a reset instead of the interrupt. Go figure. */ if ( enpringput ((RING *) & pDev->enp_toenp, pBCB) == 1 ) pDev->enp_iow.hst2enp_interrupt = ENPVAL; /* Bump the statistic counter. */ pIDR->ac_if.if_opackets++; /* Release exclusive access. */ semGive (pDrvCtrl->TxSem); return (OK); }#else/********************************************************************************* enpTxStartup - kick start the transmitter after generic ether_output**/LOCAL void enpTxStartup ( DRV_CTRL * pDrvCtrl /* pointer to driver control structure */ ) { int lostCarrier; int blen; u_char *bufStart; ENPDEVICE *pDev; MBUF *pTempMbuf; BCB *pBCB; u_char *pBuf; MBUF * pMbuf; pDev = (ENPDEVICE *) pDrvCtrl->enpAddr; /* BSD 4.4 drivers already have exclusive access - no semaphore needed. */ /* some boards (eg. iv3201a,hkv2f,mv133) get bus errors with 32bit access */ READLONG (&pDev->enp_stat.e_lost_carrier, &lostCarrier); lostCarrier = ntohl (lostCarrier); if (lostCarrier > pDrvCtrl->lostCarrier) { /* The test should probably be "not equal", however, roll-over * will take a long time. After reset pDrvCtrl->lostCarrier won't * be in sync -- we should initialize (i.e. read) it elsewhere. * * Keep a separate count of lost carrier so statics don't * get messed up. */ pDrvCtrl->lostCarrier = lostCarrier;#ifdef ENP_DEBUG logMsg ("enp%d: lost carrier\n", pDrvCtrl->idr.ac_if.if_unit, 0, 0, 0, 0, 0);#endif } while (pDrvCtrl->idr.ac_if.if_snd.ifq_head) { IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* If no resource available, discard packet */ if (enpringempty ((RING *) &pDev->enp_hostfree)) { if (pMbuf != NULL) m_freem (pMbuf); break; } pBCB = (BCB *) enpringget ((RING *)&pDev->enp_hostfree); /* Get pointer to buffer to fill with outgoing packet */ READLONG ((&pBCB->b_addr), &bufStart); bufStart = (u_char *) ntohl ((int)bufStart); pBuf = bufStart; /* copy data from mbufs to enp a word at a time. * most other netif drivers use copy_from_mbufs() to accomplish * this task. we're doing this manually here because we * need to take care of a special case (hkv2f + ENP, see below). */ pTempMbuf = pMbuf; /* copy ptr */ while (pTempMbuf != NULL) { /* if destination adrs starts at odd byte boundary * copy a byte at a time. copying a word from hkv2f into ENP memory * starting at an odd byte causes problems. */ if (((int) pBuf & 1) == 1) bcopyBytes ( mtod (pTempMbuf, char *), (char *) pBuf, (int) pTempMbuf->m_len ); else { blen = pTempMbuf->m_len >> 1; /* copy 2 bytes at a time */ bcopyWords (mtod (pTempMbuf, char *), (char *) pBuf, blen); /* copy the remaining byte if any */ blen <<= 1; if (blen != pTempMbuf->m_len) { *((char *) (pBuf + blen)) = *((char *) (mtod (pTempMbuf, char *) + blen)); } } /* Move pointer ahead, and get next mbuf pointer */ pBuf += pTempMbuf->m_len; pTempMbuf = pTempMbuf->m_next; } /* Done with mbufs, release them to system */ m_freem (pMbuf); /* Set length of packet */ blen = max ( MINPKTSIZE, ((int) pBuf - (int) bufStart) ); pBCB->b_len = htons (blen); /* Put the BCB on the outgoing ring, and if this is the only entry on * the ring, generate an interrupt to the ENP by writing to the special * location in the shared memory space. Some boards require this * interrupt, while others work fine without it, and still others * perform a reset instead of the interrupt. Go figure. */ if ( enpringput ((RING *) & pDev->enp_toenp, pBCB) == 1 ) pDev->enp_iow.hst2enp_interrupt = ENPVAL; /* Bump the statistic counter. */ pDrvCtrl->idr.ac_if.if_opackets++; } return; }#endif/********************************************************************************* enpIoctl - ioctl for interface** RETURNS: 0, or EINVAL*/LOCAL int enpIoctl ( IDR *pIDR, int cmd, caddr_t data ) { int error; ENPDEVICE* pEnpDev; DRV_CTRL* pDrvCtrl; pDrvCtrl = & drvCtrl [pIDR->ac_if.if_unit];#ifdef ENP_DEBUG printf ( "enp: ioctl: pIDR=%x, cmd=%x, data=%x\n", pIDR, cmd, data );#endif error = 0; switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIDR, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* set promiscuous bit according to flags */ if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) { pEnpDev = pDrvCtrl->enpAddr; pEnpDev->enp_mode |= 0x1000; } else { pEnpDev = pDrvCtrl->enpAddr; pEnpDev->enp_mode &= ~0x1000; } break; /* Just set the thing into promiscuous mode. */ case SIOCADDMULTI: case SIOCDELMULTI: pEnpDev = pDrvCtrl->enpAddr; pEnpDev->enp_mode |= 0x1000; break; default: error = EINVAL; } return (error); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -