예제 #1
0
/*
 * VCC has been finally closed.
 */
void
hatm_vcc_closed(struct hatm_softc *sc, u_int cid)
{
	struct hevcc *vcc = sc->vccs[cid];

	/* inform management about non-NG and NG-PVCs */
	if (!(vcc->param.flags & ATMIO_FLAG_NG) ||
	    (vcc->param.flags & ATMIO_FLAG_PVC))
		ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), HE_VPI(cid), HE_VCI(cid), 0);

	sc->open_vccs--;
	uma_zfree(sc->vcc_zone, vcc);
	sc->vccs[cid] = NULL;
}
예제 #2
0
void
hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0,
    u_int len)
{
	struct hevcc *vcc;
	struct atm_pseudohdr aph;
	struct mbuf *m, *m1;
	u_int vpi, vci;
	u_char *ptr;

	DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0));

	vcc = sc->vccs[cid];
	if (vcc == NULL)
		goto drop;

	if (flags & HE_REGM_RBRQ_CON_CLOSED) {
		if (vcc->vflags & HE_VCC_RX_CLOSING) {
			vcc->vflags &= ~HE_VCC_RX_CLOSING;
			if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
				if (!(vcc->vflags & HE_VCC_OPEN))
					hatm_vcc_closed(sc, cid);
			} else
				cv_signal(&sc->vcc_cv);
		}
		goto drop;
	}

	if (!(vcc->vflags & HE_VCC_RX_OPEN))
		goto drop;

	if (flags & HE_REGM_RBRQ_HBUF_ERROR) {
		sc->istats.hbuf_error++;
		if (vcc->chain != NULL) {
			m_freem(vcc->chain);
			vcc->chain = vcc->last = NULL;
		}
		goto drop;
	}
	if (m0 == NULL) {
		sc->istats.no_rcv_mbuf++;
		return;
	}

	if ((m0->m_len = len) == 0) {
		sc->istats.empty_hbuf++;
		m_free(m0);

	} else if (vcc->chain == NULL) {
		sc->istats.rx_seg++;
		vcc->chain = vcc->last = m0;
		vcc->last->m_next = NULL;
		vcc->chain->m_pkthdr.len = m0->m_len;
		vcc->chain->m_pkthdr.rcvif = sc->ifp;

	} else {
		sc->istats.rx_seg++;
		vcc->last->m_next = m0;
		vcc->last = m0;
		vcc->last->m_next = NULL;
		vcc->chain->m_pkthdr.len += m0->m_len;
	}

	if (!(flags & HE_REGM_RBRQ_END_PDU))
		return;

	if (flags & HE_REGM_RBRQ_CRC_ERROR) {
		if (vcc->chain)
			m_freem(vcc->chain);
		vcc->chain = vcc->last = NULL;
		sc->istats.crc_error++;
		sc->ifp->if_ierrors++;
		return;
	}
	if (flags & HE_REGM_RBRQ_LEN_ERROR) {
		if (vcc->chain)
			m_freem(vcc->chain);
		vcc->chain = vcc->last = NULL;
		sc->istats.len_error++;
		sc->ifp->if_ierrors++;
		return;
	}

#ifdef HATM_DEBUG
	if (sc->debug & DBG_DUMP) {
		struct mbuf *tmp;

		for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) {
			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
			for (ptr = mtod(tmp, u_char *);
			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
				printf("%02x ", *ptr);
			printf("\n");
		}
	}
#endif

	if (vcc->param.aal == ATMIO_AAL_5) {
		/*
		 * Need to remove padding and the trailer. The trailer
		 * may be split accross buffers according to 2.10.1.2
		 * Assume that mbufs sizes are even (buffer sizes and cell
		 * payload sizes are) and that there are no empty mbufs.
		 */
		m = vcc->last;
		if (m->m_len == 2) {
			/* Ah, oh, only part of CRC */
			if (m == vcc->chain) {
				/* ups */
				sc->istats.short_aal5++;
				m_freem(vcc->chain);
				vcc->chain = vcc->last = NULL;
				return;
			}
			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
				;
			ptr = (u_char *)m1->m_data + m1->m_len - 4;

		} else if (m->m_len == 4) {
			/* Ah, oh, only CRC */
			if (m == vcc->chain) {
				/* ups */
				sc->istats.short_aal5++;
				m_freem(vcc->chain);
				vcc->chain = vcc->last = NULL;
				return;
			}
			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
				;
			ptr = (u_char *)m1->m_data + m1->m_len - 2;

		} else if (m->m_len >= 6) {
			ptr = (u_char *)m->m_data + m->m_len - 6;
		} else
			panic("hatm_rx: bad mbuf len %d", m->m_len);

		len = (ptr[0] << 8) + ptr[1];
		if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
			sc->istats.badlen_aal5++;
			m_freem(vcc->chain);
			vcc->chain = vcc->last = NULL;
			return;
		}
		m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
	}
	m = vcc->chain;
	vcc->chain = vcc->last = NULL;

#ifdef ENABLE_BPF
	if (!(vcc->param.flags & ATMIO_FLAG_NG) &&
	    (vcc->param.aal == ATMIO_AAL_5) &&
	    (vcc->param.flags & ATM_PH_LLCSNAP))
		BPF_MTAP(sc->ifp, m);
#endif

	vpi = HE_VPI(cid);
	vci = HE_VCI(cid);

	ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
	ATM_PH_VPI(&aph) = vpi;
	ATM_PH_SETVCI(&aph, vci);

	sc->ifp->if_ipackets++;
	/* this is in if_atmsubr.c */
	/* sc->ifp->if_ibytes += len; */

	vcc->ibytes += len;
	vcc->ipackets++;

#if 0
	{
		struct mbuf *tmp;

		for (tmp = m; tmp != NULL; tmp = tmp->m_next) {
			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
			for (ptr = mtod(tmp, u_char *);
			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
				printf("%02x ", *ptr);
			printf("\n");
		}
	}
#endif

	atm_input(sc->ifp, &aph, m, vcc->rxhand);

	return;

  drop:
	if (m0 != NULL)
		m_free(m0);
}