Пример #1
0
static void
shmif_rcv(void *arg)
{
	struct ifnet *ifp = arg;
	struct shmif_sc *sc = ifp->if_softc;
	struct shmif_mem *busmem;
	struct mbuf *m = NULL;
	struct ether_header *eth;
	uint32_t nextpkt;
	bool wrap, passup;
	int error;
	const int align
	    = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);

 reup:
	mutex_enter(&sc->sc_mtx);
	while ((ifp->if_flags & IFF_RUNNING) == 0 && !sc->sc_dying)
		cv_wait(&sc->sc_cv, &sc->sc_mtx);
	mutex_exit(&sc->sc_mtx);

	busmem = sc->sc_busmem;

	while (ifp->if_flags & IFF_RUNNING) {
		struct shmif_pkthdr sp;

		if (m == NULL) {
			m = m_gethdr(M_WAIT, MT_DATA);
			MCLGET(m, M_WAIT);
			m->m_data += align;
		}

		DPRINTF(("waiting %d/%" PRIu64 "\n",
		    sc->sc_nextpacket, sc->sc_devgen));
		KASSERT(m->m_flags & M_EXT);

		shmif_lockbus(busmem);
		KASSERT(busmem->shm_magic == SHMIF_MAGIC);
		KASSERT(busmem->shm_gen >= sc->sc_devgen);

		/* need more data? */
		if (sc->sc_devgen == busmem->shm_gen && 
		    shmif_nextpktoff(busmem, busmem->shm_last)
		     == sc->sc_nextpacket) {
			shmif_unlockbus(busmem);
			error = 0;
			rumpcomp_shmif_watchwait(sc->sc_kq);
			if (__predict_false(error))
				printf("shmif_rcv: wait failed %d\n", error);
			membar_consumer();
			continue;
		}

		if (stillvalid_p(sc)) {
			nextpkt = sc->sc_nextpacket;
		} else {
			KASSERT(busmem->shm_gen > 0);
			nextpkt = busmem->shm_first;
			if (busmem->shm_first > busmem->shm_last)
				sc->sc_devgen = busmem->shm_gen - 1;
			else
				sc->sc_devgen = busmem->shm_gen;
			DPRINTF(("dev %p overrun, new data: %d/%" PRIu64 "\n",
			    sc, nextpkt, sc->sc_devgen));
		}

		/*
		 * If our read pointer is ahead the bus last write, our
		 * generation must be one behind.
		 */
		KASSERT(!(nextpkt > busmem->shm_last
		    && sc->sc_devgen == busmem->shm_gen));

		wrap = false;
		nextpkt = shmif_busread(busmem, &sp,
		    nextpkt, sizeof(sp), &wrap);
		KASSERT(sp.sp_len <= ETHERMTU + ETHER_HDR_LEN);
		nextpkt = shmif_busread(busmem, mtod(m, void *),
		    nextpkt, sp.sp_len, &wrap);

		DPRINTF(("shmif_rcv: read packet of length %d at %d\n",
		    sp.sp_len, nextpkt));

		sc->sc_nextpacket = nextpkt;
		shmif_unlockbus(sc->sc_busmem);

		if (wrap) {
			sc->sc_devgen++;
			DPRINTF(("dev %p generation now %" PRIu64 "\n",
			    sc, sc->sc_devgen));
		}

		/*
		 * Ignore packets too short to possibly be valid.
		 * This is hit at least for the first frame on a new bus.
		 */
		if (__predict_false(sp.sp_len < ETHER_HDR_LEN)) {
			DPRINTF(("shmif read packet len %d < ETHER_HDR_LEN\n",
			    sp.sp_len));
			continue;
		}

		m->m_len = m->m_pkthdr.len = sp.sp_len;
		m->m_pkthdr.rcvif = ifp;

		/*
		 * Test if we want to pass the packet upwards
		 */
		eth = mtod(m, struct ether_header *);
		if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
		    ETHER_ADDR_LEN) == 0) {
			passup = true;
		} else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
			passup = true;
		} else if (ifp->if_flags & IFF_PROMISC) {
			m->m_flags |= M_PROMISC;
			passup = true;
		} else {
			passup = false;
		}

		if (passup) {
			KERNEL_LOCK(1, NULL);
			bpf_mtap(ifp, m);
			ifp->if_input(ifp, m);
			KERNEL_UNLOCK_ONE(NULL);
			m = NULL;
		}
		/* else: reuse mbuf for a future packet */
	}
	m_freem(m);
	m = NULL;

	if (!sc->sc_dying)
		goto reup;

	kthread_exit(0);
}
Пример #2
0
int
main(int argc, char *argv[])
{
	struct stat sb;
	void *busmem;
	const char *pcapfile = NULL;
	uint32_t curbus, buslast;
	struct shmif_mem *bmem;
	int fd, i, ch;
	int bonus;
	char *buf;
	bool hflag = false, doswap = false;
	pcap_dumper_t *pdump;
	FILE *dumploc = stdout;

#ifdef PLATFORM_HAS_SETGETPROGNAME
	setprogname(argv[0]);
#endif

	while ((ch = getopt(argc, argv, "hp:")) != -1) {
		switch (ch) {
		case 'h':
			hflag = true;
			break;
		case 'p':
			pcapfile = optarg;
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage();

	buf = malloc(BUFSIZE);
	if (buf == NULL)
		err(1, "malloc");

	fd = open(argv[0], O_RDONLY);
	if (fd == -1)
		err(1, "open bus");

	if (fstat(fd, &sb) == -1)
		err(1, "stat");

	busmem = mmap(NULL, sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
	if (busmem == MAP_FAILED)
		err(1, "mmap");
	bmem = busmem;

	if (bmem->shm_magic != SHMIF_MAGIC) {
		if (bmem->shm_magic != bswap32(SHMIF_MAGIC))
			errx(1, "%s not a shmif bus", argv[0]);
		doswap = 1;
	}
	if (SWAPME(bmem->shm_version) != SHMIF_VERSION)
		errx(1, "bus vesrsion %d, program %d",
		    SWAPME(bmem->shm_version), SHMIF_VERSION);

	if (pcapfile && strcmp(pcapfile, "-") == 0)
		dumploc = stderr;

	fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64
	    ", firstoff: 0x%04x, lastoff: 0x%04x\n",
	    SWAPME(bmem->shm_version), SWAPME(bmem->shm_lock),
	    SWAPME64(bmem->shm_gen),
	    SWAPME(bmem->shm_first), SWAPME(bmem->shm_last));

	if (hflag)
		exit(0);

	if (pcapfile) {
		pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518);
		pdump = pcap_dump_open(pcap, pcapfile);
		if (pdump == NULL)
			err(1, "cannot open pcap dump file");
	} else {
		/* XXXgcc */
		pdump = NULL;
	}

	curbus = SWAPME(bmem->shm_first);
	buslast = SWAPME(bmem->shm_last);
	if (curbus == BUSMEM_DATASIZE)
		curbus = 0;

	bonus = 0;
	if (buslast < curbus)
		bonus = 1;

	i = 0;
	while (curbus <= buslast || bonus) {
		struct pcap_pkthdr packhdr;
		struct shmif_pkthdr sp;
		uint32_t oldoff;
		uint32_t curlen;
		bool wrap;

		assert(curbus < sb.st_size);

		wrap = false;
		oldoff = curbus;
		curbus = shmif_busread(bmem, &sp, oldoff, sizeof(sp), &wrap);
		if (wrap)
			bonus = 0;

		assert(curbus < sb.st_size);
		curlen = SWAPME(sp.sp_len);

		if (curlen == 0) {
			continue;
		}

		fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, "
			    "ts %d/%06d\n", i++, curbus,
			    curlen, SWAPME(sp.sp_sec), SWAPME(sp.sp_usec));

		if (!pcapfile) {
			curbus = shmif_busread(bmem,
			    buf, curbus, curlen, &wrap);
			if (wrap)
				bonus = 0;
			continue;
		}

		memset(&packhdr, 0, sizeof(packhdr));
		packhdr.caplen = packhdr.len = curlen;
		packhdr.ts.tv_sec = SWAPME(sp.sp_sec);
		packhdr.ts.tv_usec = SWAPME(sp.sp_usec);
		assert(curlen <= BUFSIZE);

		curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap);
		pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf);
		if (wrap)
			bonus = 0;
	}

	if (pcapfile)
		pcap_dump_close(pdump);

	return 0;
}