/** * _eth_format_packet() places the next packet to be transmitted into * the above link-layer output packet. * \return address of higher-level protocol (IP/RARP/RARP) header. */ void *_eth_formatpacket (const void *mac_dest, WORD eth_type) { SIO_TRACE (("_eth_formatpacket, type %04X", eth_type)); nw_pkt = (*mac_tx_format) (TX_BUF(), mac_dest, eth_type); return (nw_pkt); }
BOOL_32 EMAC_SendPacket(void *pPacket, UNS_32 size) { UNS_32 Index; UNS_32 IndexNext = LPC_EMAC->TxProduceIndex + 1; if(size == 0) { return(TRUE); } if(IndexNext > LPC_EMAC->TxDescriptorNumber) { IndexNext = 0; } if(IndexNext == LPC_EMAC->TxConsumeIndex) { return(FALSE); } Index = LPC_EMAC->TxProduceIndex; if (size > ETH_FRAG_SIZE) size = ETH_FRAG_SIZE; memcpy((unsigned int *)TX_BUF(Index),pPacket,size); TX_DESC_CTRL(Index) &= ~0x7ff; TX_DESC_CTRL(Index) |= (size - 1) & 0x7ff; LPC_EMAC->TxProduceIndex = IndexNext; return(TRUE); }
/* transmit packet. */ rt_err_t lpc17xx_emac_tx( rt_device_t dev, struct pbuf* p) { rt_uint32_t Index, IndexNext; struct pbuf *q; rt_uint8_t *ptr; /* calculate next index */ IndexNext = LPC_EMAC->TxProduceIndex + 1; if(IndexNext > LPC_EMAC->TxDescriptorNumber) IndexNext = 0; /* check whether block is full */ while (IndexNext == LPC_EMAC->TxConsumeIndex) { rt_err_t result; rt_uint32_t recved; /* there is no block yet, wait a flag */ result = rt_event_recv(&tx_event, 0x01, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved); RT_ASSERT(result == RT_EOK); } /* lock EMAC device */ rt_sem_take(&sem_lock, RT_WAITING_FOREVER); /* get produce index */ Index = LPC_EMAC->TxProduceIndex; /* calculate next index */ IndexNext = LPC_EMAC->TxProduceIndex + 1; if(IndexNext > LPC_EMAC->TxDescriptorNumber) IndexNext = 0; /* copy data to tx buffer */ q = p; ptr = (rt_uint8_t*)TX_BUF(Index); while (q) { memcpy(ptr, q->payload, q->len); ptr += q->len; q = q->next; } TX_DESC_CTRL(Index) &= ~0x7ff; TX_DESC_CTRL(Index) |= (p->tot_len - 1) & 0x7ff; /* change index to the next */ LPC_EMAC->TxProduceIndex = IndexNext; /* unlock EMAC device */ rt_sem_release(&sem_lock); return RT_EOK; }
static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; uint32_t Index, IndexNext; uint8_t *ptr; /* calculate next index */ IndexNext = LPC_EMAC->TxProduceIndex + 1; if(IndexNext > LPC_EMAC->TxDescriptorNumber) IndexNext = 0; #if 0 /* check whether block is full */ while (IndexNext == LPC_EMAC->TxConsumeIndex) { err_t result; uint32_t recved; /* there is no block yet, wait a flag */ result = rt_event_recv(&tx_event, 0x01, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved); } #endif Index = LPC_EMAC->TxProduceIndex; /* calculate next index */ IndexNext = LPC_EMAC->TxProduceIndex + 1; if(IndexNext > LPC_EMAC->TxDescriptorNumber) IndexNext = 0; #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif /* copy data to tx buffer */ ptr = (uint8_t*)TX_BUF(Index); for(q = p; q != NULL; q = q->next) { MEMCPY(ptr, q->payload, q->len); ptr += q->len; } TX_DESC_CTRL(Index) = (p->tot_len - 1) & 0x7ff | EMAC_TCTRL_INT | EMAC_TCTRL_LAST; /* change index to the next */ LPC_EMAC->TxProduceIndex = IndexNext; #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif LINK_STATS_INC(link.xmit); return ERR_OK; }
// Keil: function added to initialize Tx Descriptors void tx_descr_init (void) { unsigned int i; for (i = 0; i < NUM_TX_FRAG; i++) { TX_DESC_PACKET(i) = TX_BUF(i); TX_DESC_CTRL(i) = 0; TX_STAT_INFO(i) = 0; } /* Set EMAC Transmit Descriptor Registers. */ TxDescriptor = TX_DESC_BASE; TxStatus = TX_STAT_BASE; TxDescriptorNumber = NUM_TX_FRAG-1; /* Tx Descriptors Point to 0 */ TxProduceIndex = 0; }
// Keil: function added to initialize Tx Descriptors void tx_descr_init (void) { unsigned int i; for (i = 0; i < NUM_TX_FRAG; i++) { TX_DESC_PACKET(i) = TX_BUF(i); TX_DESC_CTRL(i) = 0; TX_STAT_INFO(i) = 0; } /* Set EMAC Transmit Descriptor Registers. */ MAC_TXDESCRIPTOR = TX_DESC_BASE; MAC_TXSTATUS = TX_STAT_BASE; MAC_TXDESCRIPTORNUM = NUM_TX_FRAG-1;//Minus 1 Encoding /* Tx Descriptors Point to 0 */ MAC_TXPRODUCEINDEX = 0; }
static void tx_descr_init (void) { UNS_32 i; for (i = 0; i < NUM_TX_FRAG; i++) { TX_DESC_PACKET(i) = TX_BUF(i); TX_DESC_CTRL(i) = (1<<31) | (1<<30) | (1<<29) | (1<<28) | (1<<26) | (ETH_FRAG_SIZE-1); TX_STAT_INFO(i) = 0; } /* Set EMAC Transmit Descriptor Registers. */ LPC_EMAC->TxDescriptor = TX_DESC_BASE; LPC_EMAC->TxStatus = TX_STAT_BASE; LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; /* Tx Descriptors Point to 0 */ LPC_EMAC->TxProduceIndex = 0; }
// Keil: function added to initialize Tx Descriptors void tx_descr_init (void) { unsigned int i; for (i = 0; i < NUM_TX_DESC; i++) { // Take it out!!!! TX_DESC_STAT(i) = 0; TX_DESC_CTRL(i) = 0; TX_BUFADDR(i) = 0; } for (i = 0; i < NUM_TX_DESC; i++) { TX_DESC_STAT(i) = TX_LAST_SEGM | TX_FIRST_SEGM; TX_DESC_CTRL(i) = 0; TX_BUFADDR(i) = TX_BUF(i); if (i == (NUM_TX_DESC-1)) // Last Descriptor? TX_DESC_STAT(i) |= TX_END_RING; } /* Set Starting address of RX Descriptor list */ LPC_ETHERNET->DMA_TRANS_DES_ADDR = TX_DESC_BASE; }
void Init_EthMAC(void) { unsigned int value, phyid1, phyid2; volatile unsigned int loop; unsigned phy_in_use = 0; unsigned phy_linkstatus_reg; unsigned phy_linkstatus_mask; /* Power Up the EMAC controller. */ LPC_SC->PCONP |= (0x1<<30); #if RMII LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */ LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */ LPC_IOCON->P1_1 &= ~0x07; LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */ LPC_IOCON->P1_4 &= ~0x07; LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */ LPC_IOCON->P1_8 &= ~0x07; LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */ LPC_IOCON->P1_9 &= ~0x07; LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */ LPC_IOCON->P1_10 &= ~0x07; LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */ LPC_IOCON->P1_14 &= ~0x07; LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */ LPC_IOCON->P1_15 &= ~0x07; LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */ #else LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */ LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */ LPC_IOCON->P1_1 &= ~0x07; LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */ LPC_IOCON->P1_2 &= ~0x07; LPC_IOCON->P1_2 |= 0x01; /* ENET_TXD2 */ LPC_IOCON->P1_3 &= ~0x07; LPC_IOCON->P1_3 |= 0x01; /* ENET_TXD3 */ LPC_IOCON->P1_4 &= ~0x07; LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */ LPC_IOCON->P1_5 &= ~0x07; LPC_IOCON->P1_5 |= 0x01; /* ENET_TXER */ LPC_IOCON->P1_6 &= ~0x07; LPC_IOCON->P1_6 |= 0x01; /* ENET_TX_CLK */ LPC_IOCON->P1_7 &= ~0x07; LPC_IOCON->P1_7 |= 0x01; /* ENET_COL */ LPC_IOCON->P1_8 &= ~0x07; LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */ LPC_IOCON->P1_9 &= ~0x07; LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */ LPC_IOCON->P1_10 &= ~0x07; LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */ LPC_IOCON->P1_11 &= ~0x07; LPC_IOCON->P1_11 |= 0x01; /* ENET_RXD2 */ LPC_IOCON->P1_12 &= ~0x07; LPC_IOCON->P1_12 |= 0x01; /* ENET_RXD3 */ LPC_IOCON->P1_13 &= ~0x07; LPC_IOCON->P1_13 |= 0x01; /* ENET_RX_DV */ LPC_IOCON->P1_14 &= ~0x07; LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */ LPC_IOCON->P1_15 &= ~0x07; LPC_IOCON->P1_15 |= 0x01; /* ENET_RX_CLK/ENET_REF_CLK */ #endif #if 1 LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */ LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */ LPC_IOCON->P1_17 &= ~0x07; LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */ // LPC_IOCON->LOC_ENET_MDIO = 0x01; #endif #if 0 LPC_IOCON->P2_8 &= ~0x07; /* ENET/PHY I/O config */ LPC_IOCON->P2_8 |= 0x04; /* ENET_MDC */ LPC_IOCON->P2_9 &= ~0x07; LPC_IOCON->P2_9 |= 0x04; /* ENET_MDIO */ // LPC_IOCON->LOC_ENET_MDIO = 0x00; #endif // Set up MAC Configuration Register 1 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES; // Set up MAC Command Register LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM; // Short delay for (loop = 100; loop; loop--); // Set up MAC Configuration Register 1 to pass all receive frames LPC_EMAC->MAC1 = MAC1_PASS_ALL; // Set up MAC Configuration Register 2 to append CRC and pad out frames LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; // Set Ethernet Maximum Frame Register LPC_EMAC->MAXF = ETH_MAX_FLEN; // Set Collision Window / Retry Register LPC_EMAC->CLRT = CLRT_DEF; // Set Non Back-to-Back Inter-Packet-Gap Register LPC_EMAC->IPGR = IPGR_DEF; /* Enable Reduced MII interface. */ LPC_EMAC->MCFG = MCFG_CLK_DIV64 | MCFG_RES_MII; for (loop = 100; loop; loop--); LPC_EMAC->MCFG = MCFG_CLK_DIV64; // Set MAC Command Register to enable Reduced MII interface // and prevent runt frames being filtered out LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT; // Put PHY into reset mode WriteToPHY (PHY_REG_BMCR, 0x8000); // Loop until hardware reset completes for (loop = 0; loop < 0x100000; loop++) { value = ReadFromPHY (PHY_REG_BMCR); if (!(value & 0x8000)) { // Reset has completed break; } } // Just check this actually is a DP83848C PHY phyid1 = ReadFromPHY (PHY_REG_IDR1); phyid2 = ReadFromPHY (PHY_REG_IDR2); if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DP83848C_ID) { phy_in_use = DP83848C_ID; } else if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == LAN8720_ID) { phy_in_use = LAN8720_ID; } if (phy_in_use != 0) { // Safe to configure the PHY device // Set PHY to autonegotiation link speed WriteToPHY (PHY_REG_BMCR, PHY_AUTO_NEG); // loop until autonegotiation completes for (loop = 0; loop < 0x100000; loop++) { value = ReadFromPHY (PHY_REG_BMSR); if (value & 0x0020) { // Autonegotiation has completed break; } } } // Now check the link status for (loop = 0; loop < 0x10000; loop++) { value = ReadFromPHY (PHY_REG_BMSR); if (value & 0x04) { /* bit 2 of BSR = 1? Link Up */ // The link is on break; } } // Configure the EMAC with the established parameters switch (phy_in_use) { case DP83848C_ID: value = ReadFromPHY (PHY_REG_STS); /* PHY Extended Status Register */ // Now configure for full/half duplex mode if (value & 0x0004) { // We are in full duplex is enabled mode LPC_EMAC->MAC2 |= MAC2_FULL_DUP; LPC_EMAC->Command |= CR_FULL_DUP; LPC_EMAC->IPGT = IPGT_FULL_DUP; } else { // Otherwise we are in half duplex mode LPC_EMAC->IPGT = IPGT_HALF_DUP; } // Now configure 100MBit or 10MBit mode if (value & 0x0002) { // 10MBit mode LPC_EMAC->SUPP = 0; } else { // 100MBit mode LPC_EMAC->SUPP = SUPP_SPEED; } break; case LAN8720_ID: value = ReadFromPHY (PHY_REG_SCSR); /* PHY Extended Status Register */ // Now configure for full/half duplex mode if (value & (1<<4)) { /* bit 4: 1 = Full Duplex, 0 = Half Duplex */ // We are in full duplex is enabled mode LPC_EMAC->MAC2 |= MAC2_FULL_DUP; LPC_EMAC->Command |= CR_FULL_DUP; LPC_EMAC->IPGT = IPGT_FULL_DUP; }else { // Otherwise we are in half duplex mode LPC_EMAC->IPGT = IPGT_HALF_DUP; } // Now configure 100MBit or 10MBit mode if (value & (1<<3)) { /* bit 3: 1 = 100Mbps, 0 = 10Mbps */ // 100MBit mode LPC_EMAC->SUPP = SUPP_SPEED; }else { // 10MBit mode LPC_EMAC->SUPP = 0; } break; } // Now set the Ethernet MAC Address registers // NOTE - MAC address must be unique on the network! LPC_EMAC->SA0 = (MYMAC_1 << 8) | MYMAC_2; // Station address 0 Reg LPC_EMAC->SA1 = (MYMAC_3 << 8) | MYMAC_4; // Station address 1 Reg LPC_EMAC->SA2 = (MYMAC_5 << 8) | MYMAC_6; // Station address 2 Reg // Now initialise the Rx descriptors for (loop = 0; loop < NUM_RX_FRAG; loop++) { RX_DESC_PACKET(loop) = RX_BUF(loop); RX_DESC_CTRL(loop) = RCTRL_INT | (ETH_FRAG_SIZE-1); RX_STAT_INFO(loop) = 0; RX_STAT_HASHCRC(loop) = 0; } // Set up the Receive Descriptor Base address register LPC_EMAC->RxDescriptor = RX_DESC_BASE; // Set up the Receive Status Base address register LPC_EMAC->RxStatus = RX_STAT_BASE; // Setup the Receive Number of Descriptor register LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1; // Set Receive Consume Index register to 0 LPC_EMAC->RxConsumeIndex = 0; // Now initialise the Tx descriptors for (loop = 0; loop < NUM_TX_FRAG; loop++) { TX_DESC_PACKET(loop) = TX_BUF(loop); TX_DESC_CTRL(loop) = 0; TX_STAT_INFO(loop) = 0; } // Set up the Transmit Descriptor Base address register LPC_EMAC->TxDescriptor = TX_DESC_BASE; // Set up the Transmit Status Base address register LPC_EMAC->TxStatus = TX_STAT_BASE; // Setup the Transmit Number of Descriptor register LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; // Set Transmit Consume Index register to 0 LPC_EMAC->TxProduceIndex = 0; // Receive Broadcast and Perfect Match Packets LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN; // Enable interrupts MAC Module Control Interrupt Enable Register LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE; // Reset all ethernet interrupts in MAC module LPC_EMAC->IntClear = 0xFFFF; // Finally enable receive and transmit mode in ethernet core LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); LPC_EMAC->MAC1 |= MAC1_REC_EN; }
BOOL LPC24XX_EMAC_lwip_init ( struct netif *pNetIf ) { UINT32 i; LPC24XX_EMAC & ENET = *(LPC24XX_EMAC *)LPC24XX_EMAC::c_EMAC_Base; /* Power Up the EMAC controller. */ LPC24XX::SYSCON().PCONP |= LPC24XX_SYSCON::ENABLE_ENET; /* Connect EMAC pins */ LPC24XX_EMAC_lwip_setpins( ENET_PHY_lwip_get_MII_mode() ); /* Reset EMAC */ ENET.MAC_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES; ENET.MAC_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES; HAL_Time_Sleep_MicroSeconds(1); /* Initialize MAC control registers. */ ENET.MAC_MAC1 = 0; ENET.MAC_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; ENET.MAC_MAXF = ETH_MAX_FLEN; ENET.MAC_CLRT = CLRT_DEF; ENET.MAC_IPGR = IPGR_DEF; if ( !ENET_PHY_lwip_get_MII_mode() ) { /* Enable RMII mode in MAC command register */ ENET.MAC_COMMAND = ENET.MAC_COMMAND | CR_RMII; } /* Reset MII Management hardware */ ENET.MAC_MCFG = MCFG_RES_MII; HAL_Time_Sleep_MicroSeconds(1); /* Set MDC Clock divider */ ENET.MAC_MCFG = ENET_PHY_lwip_get_MDC_Clk_Div() & MCFG_CLK_SEL; /* Initialiaze external ethernet Phy */ if ( !ENET_PHY_lwip_init() ) { return FALSE; } /* Set the Ethernet MAC Address registers */ ENET.MAC_SA2 = (pNetIf->hwaddr[1] << 8) | pNetIf->hwaddr[0]; ENET.MAC_SA1 = (pNetIf->hwaddr[3] << 8) | pNetIf->hwaddr[2]; ENET.MAC_SA0 = (pNetIf->hwaddr[5] << 8) | pNetIf->hwaddr[4]; /* Setup the Rx DMA Descriptors */ for (i = 0; i < NUM_RX_FRAG; i++) { RX_DESC_PACKET(i) = RX_BUF(i); RX_DESC_CTRL(i) = RCTRL_INT | (ETH_FRAG_SIZE-1); RX_STAT_INFO(i) = 0; RX_STAT_HASHCRC(i) = 0; } /* Set the EMAC Rx Descriptor Registers. */ ENET.MAC_RXDESCRIPTOR = RX_DESC_BASE; ENET.MAC_RXSTATUS = RX_STAT_BASE; ENET.MAC_RXDESCRIPTORNUM = NUM_RX_FRAG-1; ENET.MAC_RXCONSUMEINDEX = 0; /* Setup the Tx DMA Descriptors */ for (i = 0; i < NUM_TX_FRAG; i++) { TX_DESC_PACKET(i) = TX_BUF(i); TX_DESC_CTRL(i) = 0; TX_STAT_INFO(i) = 0; } /* Set the EMAC Tx Descriptor Registers. */ ENET.MAC_TXDESCRIPTOR = TX_DESC_BASE; ENET.MAC_TXSTATUS = TX_STAT_BASE; ENET.MAC_TXDESCRIPTORNUM = NUM_TX_FRAG-1; ENET.MAC_TXPRODUCEINDEX = 0; /* Receive Broadcast and Perfect Match Packets */ ENET.MAC_RXFILTERCTRL = RFC_PERFECT_EN | RFC_BCAST_EN; /* Enable EMAC interrupts. */ ENET.MAC_INTENABLE = INT_RX_DONE | INT_TX_DONE | INT_TX_UNDERRUN | INT_RX_OVERRUN; /* Reset all interrupts */ ENET.MAC_INTCLEAR = 0xFFFF; /* Enable receive and transmit */ ENET.MAC_COMMAND |= (CR_RX_EN | CR_TX_EN); ENET.MAC_MAC1 |= MAC1_REC_EN; return TRUE; }
/** * Initialize the network driver interface. * \return 0 okay. * \return error-code otherwise. */ int _eth_init (void) { int rc; SIO_TRACE (("_eth_init")); if (_eth_is_init) return (0); rc = pkt_eth_init (&_eth_addr); if (rc) return (rc); /* error message already printed */ /* Save our MAC-address incase we change it. Change back at exit. */ memcpy (_eth_real_addr, _eth_addr, sizeof(_eth_real_addr)); switch (_pktdevclass) { case PDCLASS_ETHER: mac_tx_format = eth_mac_format; mac_transmit = eth_mac_xmit; break; case PDCLASS_TOKEN: case PDCLASS_TOKEN_RIF: mac_tx_format = tok_mac_format; mac_transmit = tok_mac_xmit; break; case PDCLASS_FDDI: mac_tx_format = fddi_mac_format; mac_transmit = fddi_mac_xmit; break; case PDCLASS_ARCNET: mac_tx_format = arcnet_mac_format; mac_transmit = arcnet_mac_xmit; break; case PDCLASS_SLIP: case PDCLASS_PPP: case PDCLASS_AX25: /* !! for now */ mac_tx_format = null_mac_format; mac_transmit = null_mac_xmit; break; default: outsnl (_LANG("No supported driver class found")); return (WERR_NO_DRIVER); } memset (TX_BUF(), 0, sizeof(union link_Packet)); memset (&_eth_brdcast, 0xFF, sizeof(_eth_brdcast)); _eth_loop_addr[0] = 0xCF; pkt_buf_wipe(); if (!_eth_get_hwtype(NULL, &_eth_mac_len)) _eth_mac_len = sizeof(eth_address); if (!strcmp(_pktdrvrname,"NDIS3PKT")) _eth_ndis3pkt = TRUE; else if (!strcmp(_pktdrvrname,"SwsVpkt")) _eth_SwsVpkt = TRUE; _eth_is_init = TRUE; RUNDOWN_ADD (_eth_release, 10); return (0); /* everything okay */ }
/** * _eth_send() does the actual transmission once we are complete with * filling the buffer. Do any last minute patches here, like fix the * size. Send to "loopback" device if it's IP and destination matches * loopback network (127.x.x.x.). * * Return length of network-layer packet (not length of link-layer * packet). */ int _eth_send (WORD len, const void *sock, const char *file, unsigned line) { #if defined(USE_DEBUG) || defined(USE_LOOPBACK) unsigned errline = 0; #endif BOOL send_loopback_to_driver = FALSE; SIO_TRACE (("_eth_send, len %d", len)); if (!_eth_is_init) /* GvB 2002-09, Lets us run without a working eth */ { SOCK_ERRNO (ENETDOWN); return (0); } #if defined(WIN32) /* * Just a test for now; send it to the driver and look what happens.... * They go on the wire and not to the Winsock loopback provider. * No surprise here yet. */ if (loopback_mode & LBACK_MODE_WINSOCK) send_loopback_to_driver = TRUE; #endif if (proto == IP4_TYPE) { /* Sending to loopback device if IPv4. */ const in_Header *ip = (const in_Header*) nw_pkt; if (!send_loopback_to_driver && _ip4_is_loopback_addr(intel(ip->destination))) { #if defined(USE_LOOPBACK) len = send_loopback (*TX_BUF(), FALSE, &errline); #else STAT (ip4stats.ips_odropped++); /* packet dropped (null-device) */ #endif goto debug_tx; } } #if defined(USE_IPV6) else if (proto == IP6_TYPE) { const in6_Header *ip = (const in6_Header*) nw_pkt; if (!send_loopback_to_driver && IN6_IS_ADDR_LOOPBACK(&ip->destination)) { #if defined(USE_LOOPBACK) len = send_loopback (*TX_BUF(), TRUE, &errline); #else STAT (ip6stats.ip6s_odropped++); #endif goto debug_tx; } } #endif /* USE_IPV6 */ #if defined(USE_PPPOE) else if (proto == PPPOE_SESS_TYPE) { pppoe_Packet *pppoe = (pppoe_Packet*) TX_BUF()->eth.data; pppoe->length = intel16 (len+2); len += PPPOE_HDR_SIZE + 2; /* add 2 for protocol */ } #endif /* Store the last Tx CPU timestamp (for debugging). */ #if (DOSX) && !(DOSX & WINWATT) if (_dbugxmit && has_rdtsc) get_rdtsc2 (&_eth_last.tx.tstamp); #endif /* Do the MAC-dependant transmit. `len' on return is total length * of link-layer packet sent. `len' is 0 on failure. The xmit-hook * is used by e.g. libpcap/libnet. */ if (_eth_xmit_hook) len = (*_eth_xmit_hook) (TX_BUF(), len + _pkt_ip_ofs); else len = (*mac_transmit) (TX_BUF(), len + _pkt_ip_ofs); if (len > _pkt_ip_ofs) { _eth_last.tx.size = len; len -= _pkt_ip_ofs; } else { if (debug_on) outs ("Tx failed. "); len = 0; _eth_last.tx.size = 0; } debug_tx: #if defined(NEED_PKT_SPLIT) pkt_split_mac_out (TX_BUF()); #endif #if defined(USE_STATISTICS) if (len > 0) update_out_stat(); #endif #if defined(USE_DEBUG) if (_dbugxmit) (*_dbugxmit) (sock, (const in_Header*)nw_pkt, file, line); if (len == 0) { if (errline && !send_loopback_to_driver) dbug_printf ("** Error in loopback handler, line %u\n", errline); else { const char err[] = "** Transmit fault **\n"; TCP_CONSOLE_MSG (0, ("%s", err)); dbug_printf (err); } } #else ARGSUSED (sock); ARGSUSED (file); ARGSUSED (line); #endif /* Undo hack done in pppoe_mac_format() */ if (proto == PPPOE_SESS_TYPE || _pktdevclass == PDCLASS_ETHER) _pkt_ip_ofs = sizeof(eth_Header); return (len); }