socsvn commit: r288633 - soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve

iateaca at FreeBSD.org iateaca at FreeBSD.org
Tue Jul 21 18:14:12 UTC 2015


Author: iateaca
Date: Tue Jul 21 18:14:10 2015
New Revision: 288633
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=288633

Log:
  add support for the read-only registers in page0 and handle the monitor mode

Modified:
  soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c

Modified: soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c
==============================================================================
--- soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c	Tue Jul 21 17:19:03 2015	(r288632)
+++ soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c	Tue Jul 21 18:14:10 2015	(r288633)
@@ -34,10 +34,11 @@
 #define NE2000_P1	1
 #define NE2000_P2	2
 #define NE2000_P3	3
+#define NE2000_P0_RO	4
 
 #define NE2000_MEM_SIZE		32768
 #define NE2000_PAGE_SIZE	0x10
-#define NE2000_PAGE_COUNT	4
+#define NE2000_PAGE_COUNT	5
 
 #define NE2000_BAR_NIC		0
 #define NE2000_BAR_ASIC		1
@@ -98,7 +99,7 @@
 static void
 ne2000_set_reg_by_offset(struct pci_ne2000_softc *sc, uint8_t page,
 		uint8_t offset, uint8_t value);
-static int
+static uint8_t
 ne2000_get_reg_by_offset(struct pci_ne2000_softc *sc, uint8_t page,
 		uint8_t offset);
 static void
@@ -158,7 +159,7 @@
 	sc->nic_regs[page][offset] = value;
 }
 
-static int
+static uint8_t
 ne2000_get_reg_by_offset(struct pci_ne2000_softc *sc, uint8_t page,
 		uint8_t offset)
 {
@@ -270,11 +271,8 @@
 
 	DPRINTF("Receive Packet: from tap interface of %zd bytes", read_len);
 
-	if (!ne2000_ether_frame_is_valid(sc))
-		return -1;
-
-	if (!ne2000_receive_ring_is_valid(sc)) {
-		DPRINTF("Drop the packet since the ring is not valid");
+	if (!ne2000_ether_frame_is_valid(sc)) {
+		DPRINTF("Drop the packet since the ether frame did not match");
 		return 0;
 	}
 
@@ -305,10 +303,11 @@
 	DPRINTF("Receive Packet: size: %d psize: %d next_curr: %d index: %d",
 			size, psize, next_curr, index);
 
-	ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_RSR, 0xff, ED_RSR_PRX);
+	ne2000_set_field_by_offset(sc, NE2000_P0_RO, ED_P0_RSR,
+			0xff, ED_RSR_PRX);
 
 	ed_hdr = (struct ed_ring *)(sc->ram + index);
-	ed_hdr->rsr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_RSR);
+	ed_hdr->rsr = ne2000_get_reg_by_offset(sc, NE2000_P0_RO, ED_P0_RSR);
 	ed_hdr->next_packet = next_curr;
 	ed_hdr->count = size + sizeof(struct ed_ring);
 
@@ -383,6 +382,8 @@
 	uint8_t curr = 0;
 	uint8_t bnry = 0;
 
+	assert(ne2000_receive_ring_is_valid(sc));
+
 	pstart = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_PSTART);
 	pstop = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_PSTOP);
 	curr = ne2000_get_reg_by_offset(sc, NE2000_P1, ED_P1_CURR);
@@ -407,10 +408,15 @@
 static int
 ne2000_ether_frame_is_valid(struct pci_ne2000_softc *sc)
 {
-	/*
-	 * TODO implement a better validation taking in consideration the
-	 * Receiver Configuration Register (RCR) and maybe the frame's CRC
-	 */
+	uint8_t rcr = 0;
+	uint8_t broadcast_addr[] = {[0 ... (ETHER_ADDR_LEN - 1)] = 0xff};
+
+	rcr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_RCR);
+
+	if (rcr & ED_RCR_MON) {
+		DPRINTF("The NIC card is in Monitor Mode");
+		return 0;
+	}
 
 	/* is valid if the destination MAC matches the NIC's address */
 	if (sc->rcv_buf[0] == sc->ram[0] &&
@@ -422,13 +428,10 @@
 		return 1;
 
 	/* is valid if the destination MAC is the broadcast address */
-	if (sc->rcv_buf[0] == 0xff &&
-	    sc->rcv_buf[1] == 0xff &&
-	    sc->rcv_buf[2] == 0xff &&
-	    sc->rcv_buf[3] == 0xff &&
-	    sc->rcv_buf[4] == 0xff &&
-	    sc->rcv_buf[5] == 0xff)
-		return 1;
+	if (rcr & ED_RCR_AB) {
+		if (memcmp(sc->rcv_buf, broadcast_addr, ETHER_ADDR_LEN) == 0)
+			return 1;
+	}
 
 	return 0;
 }
@@ -771,6 +774,9 @@
 		ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_ISR, value, 0);
 		pci_ne2000_update_intr(sc);
 		break;
+	case ED_P0_RCR:
+		DPRINTF("RCR Register: %d", value);
+		break;
 	}
 
 	return 0;
@@ -835,17 +841,41 @@
 {
 	uint8_t value = 0;
 
-	/* check is not a RTL8029 Register Defined in Page0 */
+	/*
+	 * check is either a RTL8029 Register Defined in Page0
+	 * or is a read-only Register Defined in Page0
+	 */
 	if (sc->page == NE2000_P0) {
-		if (offset == ED_RTL80X9_80X9ID0)
-			return ED_RTL80X9_ID0;
-		else if (offset == ED_RTL80X9_80X9ID1)
-			return ED_RTL8029_ID1;
+		switch (offset) {
+		case ED_RTL80X9_80X9ID0:
+			value = ED_RTL80X9_ID0;
+			break;
+		case ED_RTL80X9_80X9ID1:
+			value = ED_RTL8029_ID1;
+			break;
+		case ED_P0_CLDA0:
+		case ED_P0_CLDA1:
+		case ED_P0_TSR:
+		case ED_P0_NCR:
+		case ED_P0_FIFO:
+		case ED_P0_CRDA0:
+		case ED_P0_CRDA1:
+		case ED_P0_RSR:
+		case ED_P0_CNTR0:
+		case ED_P0_CNTR1:
+		case ED_P0_CNTR2:
+			/* read a read-only register from page 0 */
+			value = ne2000_get_reg_by_offset(sc, NE2000_P0_RO, offset);
+			break;
+		default:
+			value = ne2000_get_reg_by_offset(sc, NE2000_P0, offset);
+			break;
+		}
+	} else {
+		/* read a general NE2000 register */
+		value = ne2000_get_reg_by_offset(sc, sc->page, offset);
 	}
 
-	/* read a general NE2000 register */
-	value = ne2000_get_reg_by_offset(sc, sc->page, offset);
-
 	return value;
 }
 


More information about the svn-soc-all mailing list