Date: Fri, 10 Jul 2015 14:51:13 GMT From: iateaca@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r288190 - soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve Message-ID: <201507101451.t6AEpDxH027534@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: iateaca Date: Fri Jul 10 14:51:13 2015 New Revision: 288190 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=288190 Log: implement the reception protocol of the NE2000 nic card 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 Fri Jul 10 13:54:03 2015 (r288189) +++ soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c Fri Jul 10 14:51:13 2015 (r288190) @@ -53,6 +53,9 @@ #define MAX_INPUT_LEN 32 +#define ETHER_MAX_FRAME_LEN (ETHER_MAX_LEN - ETHER_CRC_LEN) +#define ETHER_MIN_FRAME_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) + /* * NE2000 data structures */ @@ -74,6 +77,7 @@ /* NIC memory is 16k */ uint8_t ram[NE2000_MEM_SIZE]; + uint8_t rcv_buf[ETHER_MAX_FRAME_LEN]; }; /* @@ -132,6 +136,11 @@ static int ne2000_receive_ring_is_valid(struct pci_ne2000_softc *sc); +static int +ne2000_receive_ring_is_full(struct pci_ne2000_softc *sc); + +static int +ne2000_ether_frame_is_valid(struct pci_ne2000_softc *sc); static int ne2000_parse_input(char *opts, char *tap_name, uint8_t *mac); @@ -239,13 +248,86 @@ static int ne2000_tap_rx(struct pci_ne2000_softc *sc) { - uint8_t dummybuf[2048]; - ssize_t read_len; + uint8_t pstart = 0; + uint8_t pstop = 0; + uint8_t curr = 0; + uint8_t next_curr = 0; + uint8_t psize = 0; - read_len = read(sc->tapfd, dummybuf, sizeof(dummybuf)); + uint32_t size = 0; + uint32_t tmp_size = 0; + uint32_t index = 0; + uint32_t start = 0; + uint32_t stop = 0; + + ssize_t read_len = 0; + + struct ed_ring *ed_hdr = NULL; + + memset(sc->rcv_buf, 0, ETHER_MAX_FRAME_LEN); + read_len = read(sc->tapfd, sc->rcv_buf, ETHER_MAX_FRAME_LEN); + assert(read_len > 0); 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"); + return 0; + } + + if (ne2000_receive_ring_is_full(sc)) { + DPRINTF("Drop the packet since the ring is full"); + return 0; + } + + size = read_len < ETHER_MIN_FRAME_LEN ? ETHER_MIN_FRAME_LEN : read_len; + + /* psize is the number of pages used by the frame and ne2000 header */ + psize = (size + sizeof(struct ed_ring) + (ED_PAGE_SIZE - 1)) / + ED_PAGE_SIZE; + assert(psize <= 6); + + 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); + + start = pstart * ED_PAGE_SIZE; + stop = pstop * ED_PAGE_SIZE; + index = curr * ED_PAGE_SIZE; + + next_curr = curr + psize; + if (next_curr >= pstop) + next_curr -= (pstop - pstart); + + 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); + + ed_hdr = (struct ed_ring *)(sc->ram + index); + ed_hdr->rsr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_RSR); + ed_hdr->next_packet = next_curr; + ed_hdr->count = size + sizeof(struct ed_ring); + + index += sizeof(struct ed_ring); + + if (index + size >= stop) { + tmp_size = stop - index; + memcpy(sc->ram + index, sc->rcv_buf, tmp_size); + index = start; + size -= tmp_size; + } + memcpy(sc->ram + index, sc->rcv_buf + tmp_size, size); + + ne2000_set_reg_by_offset(sc, NE2000_P1, ED_P1_CURR, next_curr); + ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_ISR, + ED_ISR_PRX, ED_ISR_PRX); + + pci_ne2000_update_intr(sc); + return 0; } @@ -288,6 +370,70 @@ } static int +ne2000_receive_ring_is_full(struct pci_ne2000_softc *sc) +{ + uint32_t avail = 0; + uint32_t start = 0; + uint32_t stop = 0; + uint32_t index = 0; + uint32_t boundary = 0; + + uint8_t pstart = 0; + uint8_t pstop = 0; + uint8_t curr = 0; + uint8_t bnry = 0; + + 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); + bnry = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_BNRY); + + index = curr * ED_PAGE_SIZE; + boundary = bnry * ED_PAGE_SIZE; + start = pstart * ED_PAGE_SIZE; + stop = pstop * ED_PAGE_SIZE; + + if (index < boundary) + avail = boundary - index; + else + avail = (stop - start) - (index - boundary); + + if (avail < (ETHER_MAX_FRAME_LEN + sizeof(struct ed_ring))) + return 1; + + return 0; +} + +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 + */ + + /* is valid if the destination MAC matches the NIC's address */ + if (sc->rcv_buf[0] == sc->ram[0] && + sc->rcv_buf[1] == sc->ram[2] && + sc->rcv_buf[2] == sc->ram[4] && + sc->rcv_buf[3] == sc->ram[6] && + sc->rcv_buf[4] == sc->ram[8] && + sc->rcv_buf[5] == sc->ram[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; + + return 0; +} + +static int ne2000_parse_input(char *opts, char *tap_name, uint8_t *mac) { uint8_t len = 0; @@ -442,7 +588,8 @@ } } - ne2000_set_reg_by_offset(sc, sc->page, offset, value); + if (!(sc->page == NE2000_P0 && offset == ED_P0_ISR)) + ne2000_set_reg_by_offset(sc, sc->page, offset, value); if (sc->page == NE2000_P0) { err = ne2000_emul_reg_page0(sc, offset, value); @@ -620,6 +767,7 @@ assert(value >= pstart && value < pstop); break; case ED_P0_ISR: + DPRINTF("ISR Register: %d", value); ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_ISR, value, 0); pci_ne2000_update_intr(sc); break;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507101451.t6AEpDxH027534>