Ejemplo n.º 1
0
OM_uint32
gss_unwrap(OM_uint32 *minor_status,
    const gss_ctx_id_t ctx,
    const gss_buffer_t input_message_buffer,
    gss_buffer_t output_message_buffer,
    int *conf_state,
    gss_qop_t *qop_state)
{
	OM_uint32 maj_stat;
	struct mbuf *m;

	if (!ctx) {
		*minor_status = 0;
		return (GSS_S_NO_CONTEXT);
	}

	MGET(m, M_WAITOK, MT_DATA);
	if (input_message_buffer->length > MLEN)
		MCLGET(m, M_WAITOK);
	m_append(m, input_message_buffer->length, input_message_buffer->value);

	maj_stat = KGSS_UNWRAP(ctx, minor_status, &m, conf_state, qop_state);

	/*
	 * On success, m is the wrapped message, on failure, m is
	 * freed.
	 */
	if (maj_stat == GSS_S_COMPLETE) {
		output_message_buffer->length = m_length(m, NULL);
		output_message_buffer->value =
			malloc(output_message_buffer->length,
			    M_GSSAPI, M_WAITOK);
		m_copydata(m, 0, output_message_buffer->length,
		    output_message_buffer->value);
		m_freem(m);
	}

	return (maj_stat);
}
Ejemplo n.º 2
0
int
cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx)
{
    usbf_status err;

    m_copydata(m, 0, m->m_pkthdr.len, sc->sc_buffer_in);
    /* NO CRC */

    usbf_setup_xfer(sc->sc_xfer_in, sc->sc_pipe_in, sc, sc->sc_buffer_in,
                    m->m_pkthdr.len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
                    10000, cdcef_txeof);

    err = usbf_transfer(sc->sc_xfer_in);
    if (err && err != USBD_IN_PROGRESS) {
        printf("encap error\n");
        cdcef_stop(sc);
        return (EIO);
    }
    sc->sc_xmit_mbuf = m;

    return (0);
}
Ejemplo n.º 3
0
static void
ntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
    void *offset)
{
	struct ntb_payload_header *hdr;

	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
	if (entry->buf != NULL)
		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);

	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
	    sizeof(struct ntb_payload_header));
	hdr->len = entry->len; /* TODO: replace with bus_space_write */
	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
	wmb();
	/* TODO: replace with bus_space_write */
	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;

	ntb_ring_sdb(qp->ntb, qp->qp_num);

	/* 
	 * The entry length can only be zero if the packet is intended to be a
	 * "link down" or similar.  Since no payload is being sent in these
	 * cases, there is nothing to add to the completion queue.
	 */
	if (entry->len > 0) {
		qp->tx_bytes += entry->len;

		if (qp->tx_handler)
			qp->tx_handler(qp, qp->cb_data, entry->cb_data,
				       entry->len);
	}

	CTR2(KTR_NTB,
	    "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry,
	    hdr->ver);
	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
}
Ejemplo n.º 4
0
void
compat_wifi_output (struct mbuf *m)
{
  sgIP_memblock *packet;
  size_t size = 0;
  struct mbuf *l;

  /* compute total size of the packet  */
  for (l = m; l != NULL; l = l->m_next)
    size += l->m_len;

  /* allocate memblock */
  packet = sgIP_memblock_allocHW (14, size - 14);

  /* copy data from mbuf to memblock */
  m_copydata (m, 0, size, packet->datastart);

  /* call TransmitFunction */
  hw.TransmitFunction (&hw, packet);

  /* free mbuf */
  m_freem (m);
}
Ejemplo n.º 5
0
/*
 * Start transfer from internal queue
 */
static int
lgue_start_transfer(struct lgue_softc *sc) {
	usbd_status err;
	struct lgue_queue_entry *entry;
	struct ifnet *ifp;

	if (STAILQ_EMPTY(&sc->lgue_tx_queue))
		return(0);

	ifp = &sc->lgue_arpcom.ac_if;
	entry = STAILQ_FIRST(&sc->lgue_tx_queue);
	STAILQ_REMOVE_HEAD(&sc->lgue_tx_queue, entry_next);

	m_copydata(entry->entry_mbuf, 0, entry->entry_mbuf->m_pkthdr.len,
	    sc->lgue_tx_buf);

	/* Transmit */
	usbd_setup_xfer(sc->lgue_tx_xfer, sc->lgue_ep[LGUE_ENDPT_TX], sc,
	    sc->lgue_tx_buf, entry->entry_mbuf->m_pkthdr.len,
	    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_txeof);
	err = usbd_transfer(sc->lgue_tx_xfer);
	if (err != USBD_IN_PROGRESS) {
		m_freem(entry->entry_mbuf);
		kfree(entry, M_USBDEV);
		lgue_stop(sc);
		ifq_clr_oactive(&ifp->if_snd);
		return(EIO);
	}

	m_freem(entry->entry_mbuf);
	kfree(entry, M_USBDEV);

	sc->lgue_tx_cnt++;
	ifq_set_oactive(&ifp->if_snd);
	ifp->if_timer = 5;
	return(0);
}
Ejemplo n.º 6
0
int
an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
{
	int error, len, cnt;

	if (off == -1)
		off = sc->sc_bap_off;
	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
		if ((error = an_seek_bap(sc, id, off)) != 0)
			return EIO;
	}

	for (len = 0; m != NULL; m = m->m_next) {
		if (m->m_len == 0)
			continue;
		len = min(m->m_len, totlen);

		if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
			m_copydata(m, 0, totlen, (caddr_t)&sc->sc_buf.sc_txbuf);
			cnt = (totlen + 1) / 2;
			an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt); 
			CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
			    sc->sc_buf.sc_val, cnt);
			off += cnt * 2;
			break;
		}
		cnt = len / 2;
		an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt); 
		CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
		    cnt);
		off += len;
		totlen -= len;
	}
	sc->sc_bap_off = off;
	return 0;
}
Ejemplo n.º 7
0
/*
 * m_megapullup() - this function is a big hack.
 * Thankfully, it's only used in ng_nat and ipfw+nat.
 *
 * It allocates an mbuf with cluster and copies the specified part of the chain
 * into cluster, so that it is all contiguous and can be accessed via a plain
 * (char *) pointer. This is required, because libalias doesn't know how to
 * handle mbuf chains.
 *
 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
 * the input packet, on failure NULL. The input packet is always consumed.
 */
struct mbuf *
m_megapullup(struct mbuf *m, int len) {
	struct mbuf *mcl;

	if (len > m->m_pkthdr.len)
		goto bad;

	if (m->m_next == NULL && M_WRITABLE(m))
		return (m);

	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
	if (mcl == NULL)
		goto bad;
	m_align(mcl, len);
	m_move_pkthdr(mcl, m);
	m_copydata(m, 0, len, mtod(mcl, caddr_t));
	mcl->m_len = mcl->m_pkthdr.len = len;
	m_freem(m);

	return (mcl);
bad:
	m_freem(m);
	return (NULL);
}
Ejemplo n.º 8
0
static void
btsco_sco_input(void *arg, struct mbuf *m)
{
	struct btsco_softc *sc = arg;
	int len;

	DPRINTFN(10, "%s len=%d\n", sc->sc_name, m->m_pkthdr.len);

	mutex_enter(&sc->sc_intr_lock);
	if (sc->sc_rx_want == 0) {
		m_freem(m);
	} else {
		KASSERT(sc->sc_rx_intr != NULL);
		KASSERT(sc->sc_rx_block != NULL);

		len = MIN(sc->sc_rx_want, m->m_pkthdr.len);
		m_copydata(m, 0, len, sc->sc_rx_block);

		sc->sc_rx_want -= len;
		sc->sc_rx_block += len;

		if (len > m->m_pkthdr.len) {
			if (sc->sc_rx_mbuf != NULL)
				m_freem(sc->sc_rx_mbuf);

			m_adj(m, len);
			sc->sc_rx_mbuf = m;
		} else {
			m_freem(m);
		}

		if (sc->sc_rx_want == 0)
			(*sc->sc_rx_intr)(sc->sc_rx_intrarg);
	}
	mutex_exit(&sc->sc_intr_lock);
}
Ejemplo n.º 9
0
static int
do_rx_iscsi_hdr(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
{
	struct adapter *sc = iq->adapter;
	struct cpl_iscsi_hdr *cpl = mtod(m, struct cpl_iscsi_hdr *);
	u_int tid = GET_TID(cpl);
	struct toepcb *toep = lookup_tid(sc, tid);
	struct icl_pdu *ip;
	struct icl_cxgbei_pdu *icp;
	uint16_t len_ddp = be16toh(cpl->pdu_len_ddp);
	uint16_t len = be16toh(cpl->len);

	M_ASSERTPKTHDR(m);
	MPASS(m->m_pkthdr.len == len + sizeof(*cpl));

	ip = icl_cxgbei_new_pdu(M_NOWAIT);
	if (ip == NULL)
		CXGBE_UNIMPLEMENTED("PDU allocation failure");
	m_copydata(m, sizeof(*cpl), ISCSI_BHS_SIZE, (caddr_t)ip->ip_bhs);
	ip->ip_data_len = G_ISCSI_PDU_LEN(len_ddp) - len;
	icp = ip_to_icp(ip);
	icp->icp_seq = ntohl(cpl->seq);
	icp->icp_flags = ICPF_RX_HDR;

	/* This is the start of a new PDU.  There should be no old state. */
	MPASS(toep->ulpcb2 == NULL);
	toep->ulpcb2 = icp;

#if 0
	CTR5(KTR_CXGBE, "%s: tid %u, cpl->len %u, pdu_len_ddp 0x%04x, icp %p",
	    __func__, tid, len, len_ddp, icp);
#endif

	m_freem(m);
	return (0);
}
Ejemplo n.º 10
0
/*
 * ipsec_common_input gets called when an IPsec-protected packet
 * is received by IPv4 or IPv6.  Its job is to find the right SA
 * and call the appropriate transform.  The transform callback
 * takes care of further processing (like ingress filtering).
 */
int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
{
	char buf[INET6_ADDRSTRLEN];
	union sockaddr_union dst_address;
	struct secasvar *sav;
	u_int32_t spi;
	int error;
#ifdef INET
#ifdef IPSEC_NAT_T
	struct m_tag *tag;
#endif
#endif

	IPSEC_ISTAT(sproto, input);

	IPSEC_ASSERT(m != NULL, ("null packet"));

	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
		sproto == IPPROTO_IPCOMP,
		("unexpected security protocol %u", sproto));

	if ((sproto == IPPROTO_ESP && !V_esp_enable) ||
	    (sproto == IPPROTO_AH && !V_ah_enable) ||
	    (sproto == IPPROTO_IPCOMP && !V_ipcomp_enable)) {
		m_freem(m);
		IPSEC_ISTAT(sproto, pdrops);
		return EOPNOTSUPP;
	}

	if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
		m_freem(m);
		IPSEC_ISTAT(sproto, hdrops);
		DPRINTF(("%s: packet too small\n", __func__));
		return EINVAL;
	}

	/* Retrieve the SPI from the relevant IPsec header */
	if (sproto == IPPROTO_ESP)
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
	else if (sproto == IPPROTO_AH)
		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
		    (caddr_t) &spi);
	else if (sproto == IPPROTO_IPCOMP) {
		u_int16_t cpi;
		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
		    (caddr_t) &cpi);
		spi = ntohl(htons(cpi));
	}

	/*
	 * Find the SA and (indirectly) call the appropriate
	 * kernel crypto routine. The resulting mbuf chain is a valid
	 * IP packet ready to go through input processing.
	 */
	bzero(&dst_address, sizeof (dst_address));
	dst_address.sa.sa_family = af;
	switch (af) {
#ifdef INET
	case AF_INET:
		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
		m_copydata(m, offsetof(struct ip, ip_dst),
		    sizeof(struct in_addr),
		    (caddr_t) &dst_address.sin.sin_addr);
#ifdef IPSEC_NAT_T
		/* Find the source port for NAT-T; see udp*_espdecap. */
		tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL);
		if (tag != NULL)
			dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1];
#endif /* IPSEC_NAT_T */
		break;
#endif /* INET */
#ifdef INET6
	case AF_INET6:
		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
		    sizeof(struct in6_addr),
		    (caddr_t) &dst_address.sin6.sin6_addr);
		/* We keep addresses in SADB without embedded scope id */
		if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
			/* XXX: sa6_recoverscope() */
			dst_address.sin6.sin6_scope_id =
			    ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
			dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
		}
		break;
#endif /* INET6 */
	default:
		DPRINTF(("%s: unsupported protocol family %u\n", __func__, af));
		m_freem(m);
		IPSEC_ISTAT(sproto, nopf);
		return EPFNOSUPPORT;
	}

	/* NB: only pass dst since key_allocsa follows RFC2401 */
	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
	if (sav == NULL) {
		DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
		    __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
		    (u_long) ntohl(spi), sproto));
		IPSEC_ISTAT(sproto, notdb);
		m_freem(m);
		return ENOENT;
	}

	if (sav->tdb_xform == NULL) {
		DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
		    __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
		    (u_long) ntohl(spi), sproto));
		IPSEC_ISTAT(sproto, noxform);
		KEY_FREESAV(&sav);
		m_freem(m);
		return ENXIO;
	}

	/*
	 * Call appropriate transform and return -- callback takes care of
	 * everything else.
	 */
	error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
	KEY_FREESAV(&sav);
	return error;
}
Ejemplo n.º 11
0
void
mec_start(struct ifnet *ifp)
{
	struct mec_softc *sc = ifp->if_softc;
	struct mbuf *m0;
	struct mec_txdesc *txd;
	struct mec_txsoft *txs;
	bus_dmamap_t dmamap;
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	uint64_t txdaddr;
	int error, firsttx, nexttx, opending;
	int len, bufoff, buflen, unaligned, txdlen;

	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
		return;

	/*
	 * Remember the previous txpending and the first transmit descriptor.
	 */
	opending = sc->sc_txpending;
	firsttx = MEC_NEXTTX(sc->sc_txlast);

	DPRINTF(MEC_DEBUG_START,
	    ("mec_start: opending = %d, firsttx = %d\n", opending, firsttx));

	for (;;) {
		/* Grab a packet off the queue. */
		IFQ_POLL(&ifp->if_snd, m0);
		if (m0 == NULL)
			break;

		if (sc->sc_txpending == MEC_NTXDESC) {
			break;
		}

		/*
		 * Get the next available transmit descriptor.
		 */
		nexttx = MEC_NEXTTX(sc->sc_txlast);
		txd = &sc->sc_txdesc[nexttx];
		txs = &sc->sc_txsoft[nexttx];

		buflen = 0;
		bufoff = 0;
		txdaddr = 0; /* XXX gcc */
		txdlen = 0; /* XXX gcc */

		len = m0->m_pkthdr.len;

		DPRINTF(MEC_DEBUG_START,
		    ("mec_start: len = %d, nexttx = %d\n", len, nexttx));

		IFQ_DEQUEUE(&ifp->if_snd, m0);
		if (len < ETHER_PAD_LEN) {
			/*
			 * I don't know if MEC chip does auto padding,
			 * so if the packet is small enough,
			 * just copy it to the buffer in txdesc.
			 * Maybe this is the simple way.
			 */
			DPRINTF(MEC_DEBUG_START, ("mec_start: short packet\n"));

			bufoff = MEC_TXD_BUFSTART(ETHER_PAD_LEN);
			m_copydata(m0, 0, m0->m_pkthdr.len,
			    txd->txd_buf + bufoff);
			memset(txd->txd_buf + bufoff + len, 0,
			    ETHER_PAD_LEN - len);
			len = buflen = ETHER_PAD_LEN;

			txs->txs_flags = MEC_TXS_TXDBUF | buflen;
		} else {
			/*
			 * If the packet won't fit the buffer in txdesc,
			 * we have to use concatenate pointer to handle it.
			 * While MEC can handle up to three segments to
			 * concatenate, MEC requires that both the second and
			 * third segments have to be 8 byte aligned.
			 * Since it's unlikely for mbuf clusters, we use
			 * only the first concatenate pointer. If the packet
			 * doesn't fit in one DMA segment, allocate new mbuf
			 * and copy the packet to it.
			 *
			 * Besides, if the start address of the first segments
			 * is not 8 byte aligned, such part have to be copied
			 * to the txdesc buffer. (XXX see below comments)
	                 */
			DPRINTF(MEC_DEBUG_START, ("mec_start: long packet\n"));

			dmamap = txs->txs_dmamap;
			if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
			    BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) {
				struct mbuf *m;

				DPRINTF(MEC_DEBUG_START,
				    ("mec_start: re-allocating mbuf\n"));
				MGETHDR(m, M_DONTWAIT, MT_DATA);
				if (m == NULL) {
					printf("%s: unable to allocate "
					    "TX mbuf\n", sc->sc_dev.dv_xname);
					break;
				}
				if (len > (MHLEN - ETHER_ALIGN)) {
					MCLGET(m, M_DONTWAIT);
					if ((m->m_flags & M_EXT) == 0) {
						printf("%s: unable to allocate "
						    "TX cluster\n",
						    sc->sc_dev.dv_xname);
						m_freem(m);
						break;
					}
				}
				/*
				 * Each packet has the Ethernet header, so
				 * in many cases the header isn't 4-byte aligned
				 * and data after the header is 4-byte aligned.
				 * Thus adding 2-byte offset before copying to
				 * new mbuf avoids unaligned copy and this may
				 * improve performance.
				 * As noted above, unaligned part has to be
				 * copied to txdesc buffer so this may cause
				 * extra copy ops, but for now MEC always
				 * requires some data in txdesc buffer,
				 * so we always have to copy some data anyway.
				 */
				m->m_data += ETHER_ALIGN;
				m_copydata(m0, 0, len, mtod(m, caddr_t));
				m->m_pkthdr.len = m->m_len = len;
				m_freem(m0);
				m0 = m;
				error = bus_dmamap_load_mbuf(sc->sc_dmat,
				    dmamap, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT);
				if (error) {
					printf("%s: unable to load TX buffer, "
					    "error = %d\n",
					    sc->sc_dev.dv_xname, error);
					m_freem(m);
					break;
				}
			}

			/* Handle unaligned part. */
			txdaddr = MEC_TXD_ROUNDUP(dmamap->dm_segs[0].ds_addr);
			txs->txs_flags = MEC_TXS_TXDPTR1;
			unaligned =
			    dmamap->dm_segs[0].ds_addr & (MEC_TXD_ALIGN - 1);
			DPRINTF(MEC_DEBUG_START,
			    ("mec_start: ds_addr = 0x%x, unaligned = %d\n",
			    (u_int)dmamap->dm_segs[0].ds_addr, unaligned));
			if (unaligned != 0) {
				buflen = MEC_TXD_ALIGN - unaligned;
				bufoff = MEC_TXD_BUFSTART(buflen);
				DPRINTF(MEC_DEBUG_START,
				    ("mec_start: unaligned, "
				    "buflen = %d, bufoff = %d\n",
				    buflen, bufoff));
				memcpy(txd->txd_buf + bufoff,
				    mtod(m0, caddr_t), buflen);
				txs->txs_flags |= MEC_TXS_TXDBUF | buflen;
			}
#if 1
			else {
				/*
				 * XXX needs hardware info XXX
				 * It seems MEC always requires some data
				 * in txd_buf[] even if buffer is
				 * 8-byte aligned otherwise DMA abort error
				 * occurs later...
				 */
				buflen = MEC_TXD_ALIGN;
				bufoff = MEC_TXD_BUFSTART(buflen);
				memcpy(txd->txd_buf + bufoff,
				    mtod(m0, caddr_t), buflen);
				DPRINTF(MEC_DEBUG_START,
				    ("mec_start: aligned, "
				    "buflen = %d, bufoff = %d\n",
				    buflen, bufoff));
				txs->txs_flags |= MEC_TXS_TXDBUF | buflen;
				txdaddr += MEC_TXD_ALIGN;
			}
#endif
			txdlen  = len - buflen;
			DPRINTF(MEC_DEBUG_START,
			    ("mec_start: txdaddr = 0x%llx, txdlen = %d\n",
			    txdaddr, txdlen));

			/*
			 * Sync the DMA map for TX mbuf.
			 *
			 * XXX unaligned part doesn't have to be sync'ed,
			 *     but it's harmless...
			 */
			bus_dmamap_sync(sc->sc_dmat, dmamap, 0,
			    dmamap->dm_mapsize,	BUS_DMASYNC_PREWRITE);
		}

#if NBPFILTER > 0
		/*
		 * Pass packet to bpf if there is a listener.
		 */
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
#endif

		/*
		 * Setup the transmit descriptor.
		 */

		/* TXINT bit will be set later on the last packet. */
		txd->txd_cmd = (len - 1);
		/* But also set TXINT bit on a half of TXDESC. */
		if (sc->sc_txpending == (MEC_NTXDESC / 2))
			txd->txd_cmd |= MEC_TXCMD_TXINT;

		if (txs->txs_flags & MEC_TXS_TXDBUF)
			txd->txd_cmd |= TXCMD_BUFSTART(MEC_TXDESCSIZE - buflen);
		if (txs->txs_flags & MEC_TXS_TXDPTR1) {
			txd->txd_cmd |= MEC_TXCMD_PTR1;
			txd->txd_ptr[0] = TXPTR_LEN(txdlen - 1) | txdaddr;
			/*
			 * Store a pointer to the packet so we can
			 * free it later.
			 */
			txs->txs_mbuf = m0;
		} else {
			txd->txd_ptr[0] = 0;
			/*
			 * In this case all data are copied to buffer in txdesc,
			 * we can free TX mbuf here.
			 */
			m_freem(m0);
		}

		DPRINTF(MEC_DEBUG_START,
		    ("mec_start: txd_cmd = 0x%llx, txd_ptr = 0x%llx\n",
		    txd->txd_cmd, txd->txd_ptr[0]));
		DPRINTF(MEC_DEBUG_START,
		    ("mec_start: len = %d (0x%04x), buflen = %d (0x%02x)\n",
		    len, len, buflen, buflen));

		/* Sync TX descriptor. */
		MEC_TXDESCSYNC(sc, nexttx,
		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

		/* Advance the TX pointer. */
		sc->sc_txpending++;
		sc->sc_txlast = nexttx;
	}

	if (sc->sc_txpending == MEC_NTXDESC) {
		/* No more slots; notify upper layer. */
		ifp->if_flags |= IFF_OACTIVE;
	}

	if (sc->sc_txpending != opending) {
		/*
		 * Cause a TX interrupt to happen on the last packet
		 * we enqueued.
		 */
		sc->sc_txdesc[sc->sc_txlast].txd_cmd |= MEC_TXCMD_TXINT;
		MEC_TXCMDSYNC(sc, sc->sc_txlast,
		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

		/* Start TX. */
		bus_space_write_8(st, sh, MEC_TX_RING_PTR,
		    MEC_NEXTTX(sc->sc_txlast));

		/*
		 * If the transmitter was idle,
		 * reset the txdirty pointer and re-enable TX interrupt.
		 */
		if (opending == 0) {
			sc->sc_txdirty = firsttx;
			bus_space_write_8(st, sh, MEC_TX_ALIAS,
			    MEC_TX_ALIAS_INT_ENABLE);
		}

		/* Set a watchdog timer in case the chip flakes out. */
		ifp->if_timer = 5;
	}
}
Ejemplo n.º 12
0
static
void
ip6_input(netmsg_t msg)
{
	struct mbuf *m = msg->packet.nm_packet;
	struct ip6_hdr *ip6;
	int off = sizeof(struct ip6_hdr), nest;
	u_int32_t plen;
	u_int32_t rtalert = ~0;
	int nxt, ours = 0, rh_present = 0;
	struct ifnet *deliverifp = NULL;
	struct in6_addr odst;
	int srcrt = 0;

#ifdef IPSEC
	/*
	 * should the inner packet be considered authentic?
	 * see comment in ah4_input().
	 */
	if (m) {
		m->m_flags &= ~M_AUTHIPHDR;
		m->m_flags &= ~M_AUTHIPDGM;
	}
#endif

	/*
	 * make sure we don't have onion peering information into m_aux.
	 */
	ip6_delaux(m);

	/*
	 * mbuf statistics
	 */
	if (m->m_flags & M_EXT) {
		if (m->m_next)
			ip6stat.ip6s_mext2m++;
		else
			ip6stat.ip6s_mext1++;
	} else {
#define M2MMAX	NELEM(ip6stat.ip6s_m2m)
		if (m->m_next) {
			if (m->m_flags & M_LOOP) {
				ip6stat.ip6s_m2m[loif[0].if_index]++;	/* XXX */
			} else if (m->m_pkthdr.rcvif->if_index < M2MMAX)
				ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
			else
				ip6stat.ip6s_m2m[0]++;
		} else
			ip6stat.ip6s_m1++;
#undef M2MMAX
	}

	in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
	ip6stat.ip6s_total++;

#ifndef PULLDOWN_TEST
	/*
	 * L2 bridge code and some other code can return mbuf chain
	 * that does not conform to KAME requirement.  too bad.
	 * XXX: fails to join if interface MTU > MCLBYTES.  jumbogram?
	 */
	if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) {
		struct mbuf *n;

		n = m_getb(m->m_pkthdr.len, MB_DONTWAIT, MT_HEADER, M_PKTHDR);
		if (n == NULL)
			goto bad;
		M_MOVE_PKTHDR(n, m);

		m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t));
		n->m_len = n->m_pkthdr.len;
		m_freem(m);
		m = n;
	}
	IP6_EXTHDR_CHECK_VOIDRET(m, 0, sizeof(struct ip6_hdr));
#endif

	if (m->m_len < sizeof(struct ip6_hdr)) {
		struct ifnet *inifp;
		inifp = m->m_pkthdr.rcvif;
		if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
			ip6stat.ip6s_toosmall++;
			in6_ifstat_inc(inifp, ifs6_in_hdrerr);
			goto bad2;
		}
	}

	ip6 = mtod(m, struct ip6_hdr *);

	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
		ip6stat.ip6s_badvers++;
		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
		goto bad;
	}

	/*
	 * Run through list of hooks for input packets.
	 *
	 * NB: Beware of the destination address changing
	 *     (e.g. by NAT rewriting). When this happens,
	 *     tell ip6_forward to do the right thing.
	 */
	if (pfil_has_hooks(&inet6_pfil_hook)) {
		odst = ip6->ip6_dst;
		if (pfil_run_hooks(&inet6_pfil_hook, &m,
		    m->m_pkthdr.rcvif, PFIL_IN)) {
			goto bad2;
		}
		if (m == NULL)			/* consumed by filter */
			goto bad2;
		ip6 = mtod(m, struct ip6_hdr *);
		srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
	}
Ejemplo n.º 13
0
static void
usie_if_rx_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct usie_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m0;
	struct mbuf *m = NULL;
	struct usie_desc *rxd;
	uint32_t actlen;
	uint16_t err;
	uint16_t pkt;
	uint16_t ipl;
	uint16_t len;
	uint16_t diff;
	uint8_t pad;
	uint8_t ipv;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(15, "rx done, actlen=%u\n", actlen);

		if (actlen < sizeof(struct usie_hip)) {
			DPRINTF("data too short %u\n", actlen);
			goto tr_setup;
		}
		m = sc->sc_rxm;
		sc->sc_rxm = NULL;

		/* fall though */
	case USB_ST_SETUP:
tr_setup:

		if (sc->sc_rxm == NULL) {
			sc->sc_rxm = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
			    MJUMPAGESIZE /* could be bigger than MCLBYTES */ );
		}
		if (sc->sc_rxm == NULL) {
			DPRINTF("could not allocate Rx mbuf\n");
			ifp->if_ierrors++;
			usbd_xfer_set_stall(xfer);
			usbd_xfer_set_frames(xfer, 0);
		} else {
			/*
			 * Directly loading a mbuf cluster into DMA to
			 * save some data copying. This works because
			 * there is only one cluster.
			 */
			usbd_xfer_set_frame_data(xfer, 0,
			    mtod(sc->sc_rxm, caddr_t), MIN(MJUMPAGESIZE, USIE_RXSZ_MAX));
			usbd_xfer_set_frames(xfer, 1);
		}
		usbd_transfer_submit(xfer);
		break;

	default:			/* Error */
		DPRINTF("USB transfer error, %s\n", usbd_errstr(error));

		if (error != USB_ERR_CANCELLED) {
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			ifp->if_ierrors++;
			goto tr_setup;
		}
		if (sc->sc_rxm != NULL) {
			m_freem(sc->sc_rxm);
			sc->sc_rxm = NULL;
		}
		break;
	}

	if (m == NULL)
		return;

	mtx_unlock(&sc->sc_mtx);

	m->m_pkthdr.len = m->m_len = actlen;

	err = pkt = 0;

	/* HW can aggregate multiple frames in a single USB xfer */
	for (;;) {
		rxd = mtod(m, struct usie_desc *);

		len = be16toh(rxd->hip.len) & USIE_HIP_IP_LEN_MASK;
		pad = (rxd->hip.id & USIE_HIP_PAD) ? 1 : 0;
		ipl = (len - pad - ETHER_HDR_LEN);
		if (ipl >= len) {
			DPRINTF("Corrupt frame\n");
			m_freem(m);
			break;
		}
		diff = sizeof(struct usie_desc) + ipl + pad;

		if (((rxd->hip.id & USIE_HIP_MASK) != USIE_HIP_IP) ||
		    (be16toh(rxd->desc_type) & USIE_TYPE_MASK) != USIE_IP_RX) {
			DPRINTF("received wrong type of packet\n");
			m->m_data += diff;
			m->m_pkthdr.len = (m->m_len -= diff);
			err++;
			if (m->m_pkthdr.len > 0)
				continue;
			m_freem(m);
			break;
		}
		switch (be16toh(rxd->ethhdr.ether_type)) {
		case ETHERTYPE_IP:
			ipv = NETISR_IP;
			break;
#ifdef INET6
		case ETHERTYPE_IPV6:
			ipv = NETISR_IPV6;
			break;
#endif
		default:
			DPRINTF("unsupported ether type\n");
			err++;
			break;
		}

		/* the last packet */
		if (m->m_pkthdr.len <= diff) {
			m->m_data += (sizeof(struct usie_desc) + pad);
			m->m_pkthdr.len = m->m_len = ipl;
			m->m_pkthdr.rcvif = ifp;
			BPF_MTAP(sc->sc_ifp, m);
			netisr_dispatch(ipv, m);
			break;
		}
		/* copy aggregated frames to another mbuf */
		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
		if (__predict_false(m0 == NULL)) {
			DPRINTF("could not allocate mbuf\n");
			err++;
			m_freem(m);
			break;
		}
		m_copydata(m, sizeof(struct usie_desc) + pad, ipl, mtod(m0, caddr_t));
		m0->m_pkthdr.rcvif = ifp;
		m0->m_pkthdr.len = m0->m_len = ipl;

		BPF_MTAP(sc->sc_ifp, m0);
		netisr_dispatch(ipv, m0);

		m->m_data += diff;
		m->m_pkthdr.len = (m->m_len -= diff);
	}

	mtx_lock(&sc->sc_mtx);

	ifp->if_ierrors += err;
	ifp->if_ipackets += pkt;
}
Ejemplo n.º 14
0
static
#ifndef GPROF
__inline
#endif
int
tcp_build_datapkt(struct tcpcb *tp, struct socket *so, int off,
    long len, int hdrlen, struct mbuf **mp)
{
	struct mbuf *m, *m0;

	if (tp->t_force && len == 1)
		tcpstat.tcps_sndprobe++;
	else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
		tcpstat.tcps_sndrexmitpack++;
		tcpstat.tcps_sndrexmitbyte += len;
	} else {
		tcpstat.tcps_sndpack++;
		tcpstat.tcps_sndbyte += len;
	}
#ifdef notyet
	if ((m = m_copypack(so->so_snd.sb_mb, off,
	    (int)len, max_linkhdr + hdrlen)) == 0)
		return (ENOBUFS);
	/*
	 * m_copypack left space for our hdr; use it.
	 */
	m->m_len += hdrlen;
	m->m_data -= hdrlen;
#else
	MGETHDR(m, M_DONTWAIT, MT_HEADER);
	if (__predict_false(m == NULL))
		return (ENOBUFS);
	MCLAIM(m, &tcp_tx_mowner);

	/*
	 * XXX Because other code assumes headers will fit in
	 * XXX one header mbuf.
	 *
	 * (This code should almost *never* be run.)
	 */
	if (__predict_false((max_linkhdr + hdrlen) > MHLEN)) {
		TCP_OUTPUT_COUNTER_INCR(&tcp_output_bigheader);
		MCLGET(m, M_DONTWAIT);
		if ((m->m_flags & M_EXT) == 0) {
			m_freem(m);
			return (ENOBUFS);
		}
	}

	m->m_data += max_linkhdr;
	m->m_len = hdrlen;

	/*
	 * To avoid traversing the whole sb_mb chain for correct
	 * data to send, remember last sent mbuf, its offset and
	 * the sent size.  When called the next time, see if the
	 * data to send is directly following the previous transfer.
	 * This is important for large TCP windows.
	 */
	if (off == 0 || tp->t_lastm == NULL ||
	    (tp->t_lastoff + tp->t_lastlen) != off) {
		TCP_OUTPUT_COUNTER_INCR(&tcp_output_predict_miss);
		/*
		 * Either a new packet or a retransmit.
		 * Start from the beginning.
		 */
		tp->t_lastm = so->so_snd.sb_mb;
		tp->t_inoff = off;
	} else {
		TCP_OUTPUT_COUNTER_INCR(&tcp_output_predict_hit);
		tp->t_inoff += tp->t_lastlen;
	}

	/* Traverse forward to next packet */
	while (tp->t_inoff > 0) {
		if (tp->t_lastm == NULL)
			panic("tp->t_lastm == NULL");
		if (tp->t_inoff < tp->t_lastm->m_len)
			break;
		tp->t_inoff -= tp->t_lastm->m_len;
		tp->t_lastm = tp->t_lastm->m_next;
	}

	tp->t_lastoff = off;
	tp->t_lastlen = len;
	m0 = tp->t_lastm;
	off = tp->t_inoff;

	if (len <= M_TRAILINGSPACE(m)) {
		m_copydata(m0, off, (int) len, mtod(m, caddr_t) + hdrlen);
		m->m_len += len;
		TCP_OUTPUT_COUNTER_INCR(&tcp_output_copysmall);
	} else {
		m->m_next = m_copy(m0, off, (int) len);
		if (m->m_next == NULL) {
			m_freem(m);
			return (ENOBUFS);
		}
#ifdef TCP_OUTPUT_COUNTERS
		if (m->m_next->m_flags & M_EXT)
			TCP_OUTPUT_COUNTER_INCR(&tcp_output_refbig);
		else
			TCP_OUTPUT_COUNTER_INCR(&tcp_output_copybig);
#endif /* TCP_OUTPUT_COUNTERS */
	}
#endif

	*mp = m;
	return (0);
}
Ejemplo n.º 15
0
/*
 * Defragment a mbuf chain, returning the shortest possible
 * chain of mbufs and clusters.  If allocation fails and
 * this cannot be completed, NULL will be returned, but
 * the passed in chain will be unchanged.  Upon success,
 * the original chain will be freed, and the new chain
 * will be returned.
 *
 * If a non-packet header is passed in, the original
 * mbuf (chain?) will be returned unharmed.
 */
struct mbuf *
m_defrag(struct mbuf *m0, int how)
{
	struct mbuf *m_new = NULL, *m_final = NULL;
	int progress = 0, length;

	MBUF_CHECKSLEEP(how);
	if (!(m0->m_flags & M_PKTHDR))
		return (m0);

	m_fixhdr(m0); /* Needed sanity check */

#ifdef MBUF_STRESS_TEST
	if (m_defragrandomfailures) {
		int temp = arc4random() & 0xff;
		if (temp == 0xba)
			goto nospace;
	}
#endif

	if (m0->m_pkthdr.len > MHLEN)
		m_final = m_getcl(how, MT_DATA, M_PKTHDR);
	else
		m_final = m_gethdr(how, MT_DATA);

	if (m_final == NULL)
		goto nospace;

	if (m_dup_pkthdr(m_final, m0, how) == 0)
		goto nospace;

	m_new = m_final;

	while (progress < m0->m_pkthdr.len) {
		length = m0->m_pkthdr.len - progress;
		if (length > MCLBYTES)
			length = MCLBYTES;

		if (m_new == NULL) {
			if (length > MLEN)
				m_new = m_getcl(how, MT_DATA, 0);
			else
				m_new = m_get(how, MT_DATA);
			if (m_new == NULL)
				goto nospace;
		}

		m_copydata(m0, progress, length, mtod(m_new, caddr_t));
		progress += length;
		m_new->m_len = length;
		if (m_new != m_final)
			m_cat(m_final, m_new);
		m_new = NULL;
	}
#ifdef MBUF_STRESS_TEST
	if (m0->m_next == NULL)
		m_defraguseless++;
#endif
	m_freem(m0);
	m0 = m_final;
#ifdef MBUF_STRESS_TEST
	m_defragpackets++;
	m_defragbytes += m0->m_pkthdr.len;
#endif
	return (m0);
nospace:
#ifdef MBUF_STRESS_TEST
	m_defragfailure++;
#endif
	if (m_final)
		m_freem(m_final);
	return (NULL);
}
Ejemplo n.º 16
0
/*
 * [remote_input] Packet, without data, from peer.  Restore pkt->info,
 * return 0 on success 
 */
int
remote_input(struct mbuf *m)
{
    u_int32_t       ip_len;
    struct remote_packet *info;
    struct packet * pkt = NULL;
    int err = 0, once = 1;
    
    mn.stats.mc_recv++;
    Dprintf(("remote_input: received foreign packet\n"), MN_P_PKTS);
    ASSERT(m);
    if (udp_validate(m)==0) {
	    printf("UDP fail\n");
	    return EINVAL;
    }
    ip_len = m->m_pkthdr.len;
    m_adj(m, sizeof(struct udpiphdr));

    while(m->m_pkthdr.len && once){
	    if (once > 46){
		    printf("remote_input: pkthdrlen(%d) once (%d)\n",m->m_pkthdr.len,once);
		    err = 1; /* too many 32 byte remote pkts in
				 1500-28 byte packet */
		    goto error;
	    }
	    once++;
	    if (m->m_pkthdr.len - sizeof(struct remote_packet) < 0){
		    printf("remote_input: m->m_pkthdr.len(%d) < sizeof(remote_packet)(%d)\n",
			   m->m_pkthdr.len, sizeof(struct remote_packet));
		    err = 1;
		    goto error;
	    }
	    info = mtod(m, struct remote_packet *);
	    pkt = malloc(sizeof(struct packet), M_MN_PKTS, M_NOWAIT);
	    if (!pkt) {
		    err = ENOBUFS;
		    goto error;
	    }
	    mn.stats.pkt_alloc++;
	    pkt->cachehost = 0;
	    pkt->info.id = (unsigned long) NULL;
	    pkt->m = NULL;
	    m_copydata(m,0,sizeof(struct remote_packet),(caddr_t)&(pkt->info));

	    m_adj(m, sizeof(struct remote_packet));
	    if (MC_PKT_PCACHED(pkt)) {
		    /* with aggregation we could have many */
		    if (!(mn.state & MN_AGGREGATE) && (ip_len !=
			sizeof(struct remote_packet) + sizeof(struct udpiphdr))) {
			    printf("modelnet: got udp of wrong size (%u != %d!)\n", ip_len,
				   sizeof(struct remote_packet) + sizeof(struct udpiphdr));
			    err = EINVAL;
			    goto error;
		    }
	    } else {                    /* unencapsulate non-cached packets */
		    /* XXX untested ! */
		    /*pkt->m = m_split(pkt->m, sizeof(struct remote_packet), M_DONTWAIT);*/
		    printf("remote_input: aggregation with non pcached pkts\n");
		    pkt->m = m;
		    m = NULL;
		    once = 0;  /* we take the rest */
	    }
	    if (info->ttl-- <= 0) {
		    DDB(printf("modelnet: ttl expired on pkt 0x%x\n", (int) info->id);
			    )
			    mn.stats.mc_ttldrops++;
		    MN_LOG_PACKET(info->src, info->dst, info->hop, 1);
		    err = EINVAL;
#ifdef DEBUG_REMOTE_INPUT
		    goto error;
#else
		    MN_FREE_PKT(pkt);
		    continue;
#endif
	    }
Ejemplo n.º 17
0
/*
 * Apply a symmetric encryption/decryption algorithm.
 */
static int
swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
    int flags)
{
	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
	unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
	struct enc_xform *exf;
	int i, k, j, blks;

	exf = sw->sw_exf;
	blks = exf->blocksize;

	/* Check for non-padded data */
	if (crd->crd_len % blks)
		return EINVAL;

	/* Initialize the IV */
	if (crd->crd_flags & CRD_F_ENCRYPT) {
		/* IV explicitly provided ? */
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, iv, blks);
		else
			arc4rand(iv, blks, 0);

		/* Do we need to write the IV */
		if (!(crd->crd_flags & CRD_F_IV_PRESENT))
			crypto_copyback(flags, buf, crd->crd_inject, blks, iv);

	} else {	/* Decryption */
			/* IV explicitly provided ? */
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, iv, blks);
		else {
			/* Get IV off buf */
			crypto_copydata(flags, buf, crd->crd_inject, blks, iv);
		}
	}

	if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
		int error; 

		if (sw->sw_kschedule)
			exf->zerokey(&(sw->sw_kschedule));
		error = exf->setkey(&sw->sw_kschedule,
				crd->crd_key, crd->crd_klen / 8);
		if (error)
			return (error);
	}

	ivp = iv;

	/*
	 * xforms that provide a reinit method perform all IV
	 * handling themselves.
	 */
	if (exf->reinit)
		exf->reinit(sw->sw_kschedule, iv);

	if (flags & CRYPTO_F_IMBUF) {
		struct mbuf *m = (struct mbuf *) buf;

		/* Find beginning of data */
		m = m_getptr(m, crd->crd_skip, &k);
		if (m == NULL)
			return EINVAL;

		i = crd->crd_len;

		while (i > 0) {
			/*
			 * If there's insufficient data at the end of
			 * an mbuf, we have to do some copying.
			 */
			if (m->m_len < k + blks && m->m_len != k) {
				m_copydata(m, k, blks, blk);

				/* Actual encryption/decryption */
				if (exf->reinit) {
					if (crd->crd_flags & CRD_F_ENCRYPT) {
						exf->encrypt(sw->sw_kschedule,
						    blk);
					} else {
						exf->decrypt(sw->sw_kschedule,
						    blk);
					}
				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
					/* XOR with previous block */
					for (j = 0; j < blks; j++)
						blk[j] ^= ivp[j];

					exf->encrypt(sw->sw_kschedule, blk);

					/*
					 * Keep encrypted block for XOR'ing
					 * with next block
					 */
					bcopy(blk, iv, blks);
					ivp = iv;
				} else {	/* decrypt */
					/*	
					 * Keep encrypted block for XOR'ing
					 * with next block
					 */
					if (ivp == iv)
						bcopy(blk, piv, blks);
					else
						bcopy(blk, iv, blks);

					exf->decrypt(sw->sw_kschedule, blk);

					/* XOR with previous block */
					for (j = 0; j < blks; j++)
						blk[j] ^= ivp[j];

					if (ivp == iv)
						bcopy(piv, iv, blks);
					else
						ivp = iv;
				}

				/* Copy back decrypted block */
				m_copyback(m, k, blks, blk);

				/* Advance pointer */
				m = m_getptr(m, k + blks, &k);
				if (m == NULL)
					return EINVAL;

				i -= blks;

				/* Could be done... */
				if (i == 0)
					break;
			}

			/* Skip possibly empty mbufs */
			if (k == m->m_len) {
				for (m = m->m_next; m && m->m_len == 0;
				    m = m->m_next)
					;
				k = 0;
			}

			/* Sanity check */
			if (m == NULL)
				return EINVAL;

			/*
			 * Warning: idat may point to garbage here, but
			 * we only use it in the while() loop, only if
			 * there are indeed enough data.
			 */
			idat = mtod(m, unsigned char *) + k;

	   		while (m->m_len >= k + blks && i > 0) {
				if (exf->reinit) {
					if (crd->crd_flags & CRD_F_ENCRYPT) {
						exf->encrypt(sw->sw_kschedule,
						    idat);
					} else {
						exf->decrypt(sw->sw_kschedule,
						    idat);
					}
				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
					/* XOR with previous block/IV */
					for (j = 0; j < blks; j++)
						idat[j] ^= ivp[j];

					exf->encrypt(sw->sw_kschedule, idat);
					ivp = idat;
				} else {	/* decrypt */
					/*
					 * Keep encrypted block to be used
					 * in next block's processing.
					 */
					if (ivp == iv)
						bcopy(idat, piv, blks);
					else
						bcopy(idat, iv, blks);

					exf->decrypt(sw->sw_kschedule, idat);

					/* XOR with previous block/IV */
					for (j = 0; j < blks; j++)
						idat[j] ^= ivp[j];

					if (ivp == iv)
						bcopy(piv, iv, blks);
					else
						ivp = iv;
				}

				idat += blks;
				k += blks;
				i -= blks;
			}
		}

		return 0; /* Done with mbuf encryption/decryption */
	} else if (flags & CRYPTO_F_IOV) {
Ejemplo n.º 18
0
/*
 * ESP input processing, called (eventually) through the protocol switch.
 */
static int
esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
	char buf[128];
	struct auth_hash *esph;
	struct enc_xform *espx;
	struct tdb_crypto *tc;
	uint8_t *ivp;
	int plen, alen, hlen;
	struct newesp *esp;
	struct cryptodesc *crde;
	struct cryptop *crp;

	IPSEC_ASSERT(sav != NULL, ("null SA"));
	IPSEC_ASSERT(sav->tdb_encalgxform != NULL, ("null encoding xform"));

	/* Valid IP Packet length ? */
	if ( (skip&3) || (m->m_pkthdr.len&3) ){
		DPRINTF(("%s: misaligned packet, skip %u pkt len %u",
				__func__, skip, m->m_pkthdr.len));
		ESPSTAT_INC(esps_badilen);
		m_freem(m);
		return EINVAL;
	}
	/* XXX don't pullup, just copy header */
	IP6_EXTHDR_GET(esp, struct newesp *, m, skip, sizeof (struct newesp));

	esph = sav->tdb_authalgxform;
	espx = sav->tdb_encalgxform;

	/* Determine the ESP header and auth length */
	if (sav->flags & SADB_X_EXT_OLD)
		hlen = sizeof (struct esp) + sav->ivlen;
	else
		hlen = sizeof (struct newesp) + sav->ivlen;

	alen = xform_ah_authsize(esph);

	/*
	 * Verify payload length is multiple of encryption algorithm
	 * block size.
	 *
	 * NB: This works for the null algorithm because the blocksize
	 *     is 4 and all packets must be 4-byte aligned regardless
	 *     of the algorithm.
	 */
	plen = m->m_pkthdr.len - (skip + hlen + alen);
	if ((plen & (espx->blocksize - 1)) || (plen <= 0)) {
		DPRINTF(("%s: payload of %d octets not a multiple of %d octets,"
		    "  SA %s/%08lx\n", __func__, plen, espx->blocksize,
		    ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
		    (u_long)ntohl(sav->spi)));
		ESPSTAT_INC(esps_badilen);
		m_freem(m);
		return EINVAL;
	}

	/*
	 * Check sequence number.
	 */
	if (esph != NULL && sav->replay != NULL &&
	    !ipsec_chkreplay(ntohl(esp->esp_seq), sav)) {
		DPRINTF(("%s: packet replay check for %s\n", __func__,
		    ipsec_logsastr(sav, buf, sizeof(buf))));	/*XXX*/
		ESPSTAT_INC(esps_replay);
		m_freem(m);
		return ENOBUFS;		/*XXX*/
	}

	/* Update the counters */
	ESPSTAT_ADD(esps_ibytes, m->m_pkthdr.len - (skip + hlen + alen));

	/* Get crypto descriptors */
	crp = crypto_getreq(esph && espx ? 2 : 1);
	if (crp == NULL) {
		DPRINTF(("%s: failed to acquire crypto descriptors\n",
			__func__));
		ESPSTAT_INC(esps_crypto);
		m_freem(m);
		return ENOBUFS;
	}

	/* Get IPsec-specific opaque pointer */
	tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto) + alen,
	    M_XDATA, M_NOWAIT | M_ZERO);
	if (tc == NULL) {
		crypto_freereq(crp);
		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
		ESPSTAT_INC(esps_crypto);
		m_freem(m);
		return ENOBUFS;
	}

	if (esph != NULL) {
		struct cryptodesc *crda = crp->crp_desc;

		IPSEC_ASSERT(crda != NULL, ("null ah crypto descriptor"));

		/* Authentication descriptor */
		crda->crd_skip = skip;
		if (SAV_ISGCM(sav))
			crda->crd_len = 8;	/* RFC4106 5, SPI + SN */
		else
			crda->crd_len = m->m_pkthdr.len - (skip + alen);
		crda->crd_inject = m->m_pkthdr.len - alen;

		crda->crd_alg = esph->type;

		/* Copy the authenticator */
		m_copydata(m, m->m_pkthdr.len - alen, alen,
		    (caddr_t) (tc + 1));

		/* Chain authentication request */
		crde = crda->crd_next;
	} else {
		crde = crp->crp_desc;
	}

	/* Crypto operation descriptor */
	crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
	crp->crp_buf = (caddr_t) m;
	crp->crp_callback = esp_input_cb;
	crp->crp_sid = sav->tdb_cryptoid;
	crp->crp_opaque = (caddr_t) tc;

	/* These are passed as-is to the callback */
	tc->tc_spi = sav->spi;
	tc->tc_dst = sav->sah->saidx.dst;
	tc->tc_proto = sav->sah->saidx.proto;
	tc->tc_protoff = protoff;
	tc->tc_skip = skip;
	KEY_ADDREFSA(sav);
	tc->tc_sav = sav;

	/* Decryption descriptor */
	IPSEC_ASSERT(crde != NULL, ("null esp crypto descriptor"));
	crde->crd_skip = skip + hlen;
	crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
	crde->crd_inject = skip + hlen - sav->ivlen;

	if (SAV_ISCTRORGCM(sav)) {
		ivp = &crde->crd_iv[0];

		/* GCM IV Format: RFC4106 4 */
		/* CTR IV Format: RFC3686 4 */
		/* Salt is last four bytes of key, RFC4106 8.1 */
		/* Nonce is last four bytes of key, RFC3686 5.1 */
		memcpy(ivp, sav->key_enc->key_data +
		    _KEYLEN(sav->key_enc) - 4, 4);

		if (SAV_ISCTR(sav)) {
			/* Initial block counter is 1, RFC3686 4 */
			be32enc(&ivp[sav->ivlen + 4], 1);
		}

		m_copydata(m, skip + hlen - sav->ivlen, sav->ivlen, &ivp[4]);
		crde->crd_flags |= CRD_F_IV_EXPLICIT;
	}

	crde->crd_alg = espx->type;

	return (crypto_dispatch(crp));
}
Ejemplo n.º 19
0
static int
do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
{
	struct adapter *sc = iq->adapter;
	struct cxgbei_data *ci = sc->iscsi_ulp_softc;
	const struct cpl_rx_data_ddp *cpl = (const void *)(rss + 1);
	u_int tid = GET_TID(cpl);
	struct toepcb *toep = lookup_tid(sc, tid);
	struct inpcb *inp = toep->inp;
	struct socket *so;
	struct sockbuf *sb;
	struct tcpcb *tp;
	struct icl_cxgbei_conn *icc;
	struct icl_conn *ic;
	struct icl_cxgbei_pdu *icp = toep->ulpcb2;
	struct icl_pdu *ip;
	u_int pdu_len, val;

	MPASS(m == NULL);

	/* Must already be assembling a PDU. */
	MPASS(icp != NULL);
	MPASS(icp->icp_flags & ICPF_RX_HDR);	/* Data is optional. */
	MPASS((icp->icp_flags & ICPF_RX_STATUS) == 0);

	pdu_len = be16toh(cpl->len);	/* includes everything. */
	val = be32toh(cpl->ddpvld);

#if 0
	CTR5(KTR_CXGBE,
	    "%s: tid %u, cpl->len %u, ddpvld 0x%08x, icp_flags 0x%08x",
	    __func__, tid, pdu_len, val, icp->icp_flags);
#endif

	icp->icp_flags |= ICPF_RX_STATUS;
	ip = &icp->ip;
	if (val & F_DDP_PADDING_ERR)
		icp->icp_flags |= ICPF_PAD_ERR;
	if (val & F_DDP_HDRCRC_ERR)
		icp->icp_flags |= ICPF_HCRC_ERR;
	if (val & F_DDP_DATACRC_ERR)
		icp->icp_flags |= ICPF_DCRC_ERR;
	if (val & F_DDP_PDU && ip->ip_data_mbuf == NULL) {
		MPASS((icp->icp_flags & ICPF_RX_FLBUF) == 0);
		MPASS(ip->ip_data_len > 0);
		icp->icp_flags |= ICPF_RX_DDP;
		counter_u64_add(ci->ddp_pdus, 1);
		counter_u64_add(ci->ddp_bytes, ip->ip_data_len);
	}

	INP_WLOCK(inp);
	if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))) {
		CTR4(KTR_CXGBE, "%s: tid %u, rx (%d bytes), inp_flags 0x%x",
		    __func__, tid, pdu_len, inp->inp_flags);
		INP_WUNLOCK(inp);
		icl_cxgbei_conn_pdu_free(NULL, ip);
#ifdef INVARIANTS
		toep->ulpcb2 = NULL;
#endif
		return (0);
	}

	tp = intotcpcb(inp);
	MPASS(icp->icp_seq == tp->rcv_nxt);
	MPASS(tp->rcv_wnd >= pdu_len);
	tp->rcv_nxt += pdu_len;
	tp->rcv_wnd -= pdu_len;
	tp->t_rcvtime = ticks;

	/* update rx credits */
	toep->rx_credits += pdu_len;
	t4_rcvd(&toep->td->tod, tp);	/* XXX: sc->tom_softc.tod */

	so = inp->inp_socket;
	sb = &so->so_rcv;
	SOCKBUF_LOCK(sb);

	icc = toep->ulpcb;
	if (__predict_false(icc == NULL || sb->sb_state & SBS_CANTRCVMORE)) {
		CTR5(KTR_CXGBE,
		    "%s: tid %u, excess rx (%d bytes), icc %p, sb_state 0x%x",
		    __func__, tid, pdu_len, icc, sb->sb_state);
		SOCKBUF_UNLOCK(sb);
		INP_WUNLOCK(inp);

		INP_INFO_RLOCK(&V_tcbinfo);
		INP_WLOCK(inp);
		tp = tcp_drop(tp, ECONNRESET);
		if (tp)
			INP_WUNLOCK(inp);
		INP_INFO_RUNLOCK(&V_tcbinfo);

		icl_cxgbei_conn_pdu_free(NULL, ip);
#ifdef INVARIANTS
		toep->ulpcb2 = NULL;
#endif
		return (0);
	}
	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
	ic = &icc->ic;
	icl_cxgbei_new_pdu_set_conn(ip, ic);

	MPASS(m == NULL); /* was unused, we'll use it now. */
	m = sbcut_locked(sb, sbused(sb)); /* XXXNP: toep->sb_cc accounting? */
	if (__predict_false(m != NULL)) {
		int len = m_length(m, NULL);

		/*
		 * PDUs were received before the tid transitioned to ULP mode.
		 * Convert them to icl_cxgbei_pdus and send them to ICL before
		 * the PDU in icp/ip.
		 */
		CTR3(KTR_CXGBE, "%s: tid %u, %u bytes in so_rcv", __func__, tid,
		    len);

		/* XXXNP: needs to be rewritten. */
		if (len == sizeof(struct iscsi_bhs) || len == 4 + sizeof(struct
		    iscsi_bhs)) {
			struct icl_cxgbei_pdu *icp0;
			struct icl_pdu *ip0;

			ip0 = icl_cxgbei_new_pdu(M_NOWAIT);
			icl_cxgbei_new_pdu_set_conn(ip0, ic);
			if (ip0 == NULL)
				CXGBE_UNIMPLEMENTED("PDU allocation failure");
			icp0 = ip_to_icp(ip0);
			icp0->icp_seq = 0; /* XXX */
			icp0->icp_flags = ICPF_RX_HDR | ICPF_RX_STATUS;
			m_copydata(m, 0, sizeof(struct iscsi_bhs), (void *)ip0->ip_bhs);
			STAILQ_INSERT_TAIL(&icc->rcvd_pdus, ip0, ip_next);
		}
		m_freem(m);
	}

	STAILQ_INSERT_TAIL(&icc->rcvd_pdus, ip, ip_next);
	if ((icc->rx_flags & RXF_ACTIVE) == 0) {
		struct cxgbei_worker_thread_softc *cwt = &cwt_softc[icc->cwt];

		mtx_lock(&cwt->cwt_lock);
		icc->rx_flags |= RXF_ACTIVE;
		TAILQ_INSERT_TAIL(&cwt->rx_head, icc, rx_link);
		if (cwt->cwt_state == CWT_SLEEPING) {
			cwt->cwt_state = CWT_RUNNING;
			cv_signal(&cwt->cwt_cv);
		}
		mtx_unlock(&cwt->cwt_lock);
	}
	SOCKBUF_UNLOCK(sb);
	INP_WUNLOCK(inp);

#ifdef INVARIANTS
	toep->ulpcb2 = NULL;
#endif

	return (0);
}
Ejemplo n.º 20
0
static void
aes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout,
    size_t skip, size_t len, void *ivec, size_t ivlen)
{
	size_t blocklen = 16, plen;
	struct {
		uint8_t cn_1[16], cn[16];
	} last2;
	int i, off, t;

	/*
	 * AES decryption with cyphertext stealing:
	 *
	 * CTSencrypt(C[0], ..., C[n], IV, K):
	 *	len = length(C[n])
	 *	E[n] = C[n-1]
	 *	X = decrypt(E[n], K)
	 *	P[n] = (X ^ C[n]){0..len-1}
	 *	E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]}
	 *	(P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K)
	 */
	plen = len % blocklen;
	if (len == blocklen) {
		/*
		 * Note: caller will ensure len >= blocklen.
		 */
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0);
	} else if (plen == 0) {
		/*
		 * This is equivalent to CBC mode followed by swapping
		 * the last two blocks.
		 */
		off = skip + len - 2 * blocklen;
		m_copydata(inout, off, 2 * blocklen, (void*) &last2);
		m_copyback(inout, off, blocklen, last2.cn);
		m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0);
	} else {
		/*
		 * This is the difficult case. We first decrypt the
		 * second to last block with a zero IV to make X. The
		 * plaintext for the last block is the XOR of X and
		 * the last cyphertext block.
		 *
		 * We derive a new cypher text for the second to last
		 * block by mixing the unused bytes of X with the last
		 * cyphertext block. The result of that can be
		 * decrypted with the rest in CBC mode.
		 */
		off = skip + len - plen - blocklen;
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, off, blocklen,
		    NULL, 0);
		m_copydata(inout, off, blocklen + plen, (void*) &last2);

		for (i = 0; i < plen; i++) {
			t = last2.cn[i];
			last2.cn[i] ^= last2.cn_1[i];
			last2.cn_1[i] = t;
		}

		m_copyback(inout, off, blocklen + plen, (void*) &last2);
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen,
		    ivec, 0);
	}

}
Ejemplo n.º 21
0
static void
aes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout,
    size_t skip, size_t len, void *ivec, size_t ivlen)
{
	size_t blocklen = 16, plen;
	struct {
		uint8_t cn_1[16], cn[16];
	} last2;
	int i, off;

	/*
	 * AES encryption with cyphertext stealing:
	 *
	 * CTSencrypt(P[0], ..., P[n], IV, K):
	 *	len = length(P[n])
	 *	(C[0], ..., C[n-2], E[n-1]) =
	 *		CBCencrypt(P[0], ..., P[n-1], IV, K)
	 *	P = pad(P[n], 0, blocksize)
	 *	E[n] = CBCencrypt(P, E[n-1], K);
	 *	C[n-1] = E[n]
	 *	C[n] = E[n-1]{0..len-1}
	 */
	plen = len % blocklen;
	if (len == blocklen) {
		/*
		 * Note: caller will ensure len >= blocklen.
		 */
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec,
		    CRD_F_ENCRYPT);
	} else if (plen == 0) {
		/*
		 * This is equivalent to CBC mode followed by swapping
		 * the last two blocks. We assume that neither of the
		 * last two blocks cross iov boundaries.
		 */
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec,
		    CRD_F_ENCRYPT);
		off = skip + len - 2 * blocklen;
		m_copydata(inout, off, 2 * blocklen, (void*) &last2);
		m_copyback(inout, off, blocklen, last2.cn);
		m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
	} else {
		/*
		 * This is the difficult case. We encrypt all but the
		 * last partial block first. We then create a padded
		 * copy of the last block and encrypt that using the
		 * second to last encrypted block as IV. Once we have
		 * the encrypted versions of the last two blocks, we
		 * reshuffle to create the final result.
		 */
		aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen,
		    ivec, CRD_F_ENCRYPT);

		/*
		 * Copy out the last two blocks, pad the last block
		 * and encrypt it. Rearrange to get the final
		 * result. The cyphertext for cn_1 is in cn. The
		 * cyphertext for cn is the first plen bytes of what
		 * is in cn_1 now.
		 */
		off = skip + len - blocklen - plen;
		m_copydata(inout, off, blocklen + plen, (void*) &last2);
		for (i = plen; i < blocklen; i++)
			last2.cn[i] = 0;
		aes_encrypt_1(ks, 0, last2.cn, 0, blocklen, last2.cn_1,
		    CRD_F_ENCRYPT);
		m_copyback(inout, off, blocklen, last2.cn);
		m_copyback(inout, off + blocklen, plen, last2.cn_1);
	}
}
Ejemplo n.º 22
0
static void
ngc_send(netmsg_t netmsg)
{
	struct socket *so = netmsg->send.base.nm_so;
	struct mbuf *m = netmsg->send.nm_m;
	struct sockaddr *addr = netmsg->send.nm_addr;
	struct mbuf *control = netmsg->send.nm_control;
	struct ngpcb *const pcbp = sotongpcb(so);
	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
	struct ng_mesg *msg;
	struct mbuf *m0;
	item_p item;
	char *path = NULL;
	int len, error = 0;
	struct ng_apply_info *apply;

#ifdef	NOTYET
	if (control && (error = ng_internalize(control, td))) {
		if (pcbp->sockdata == NULL) {
			error = ENOTCONN;
			goto release;
		}
	}
#else	/* NOTYET */
	if (control) {
		error = EINVAL;
		goto release;
	}
#endif	/* NOTYET */

	/* Require destination as there may be >= 1 hooks on this node. */
	if (addr == NULL) {
		error = EDESTADDRREQ;
		goto release;
	}

	/*
	 * Allocate an expendable buffer for the path, chop off
	 * the sockaddr header, and make sure it's NUL terminated.
	 */
	len = sap->sg_len - 2;
	path = kmalloc(len + 1, M_NETGRAPH_PATH, M_WAITOK);
	bcopy(sap->sg_data, path, len);
	path[len] = '\0';

	/*
	 * Move the actual message out of mbufs into a linear buffer.
	 * Start by adding up the size of the data. (could use mh_len?)
	 */
	for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
		len += m0->m_len;

	/*
	 * Move the data into a linear buffer as well.
	 * Messages are not delivered in mbufs.
	 */
	msg = kmalloc(len + 1, M_NETGRAPH_MSG, M_WAITOK);
	m_copydata(m, 0, len, (char *)msg);

	if (msg->header.version != NG_VERSION) {
		kfree(msg, M_NETGRAPH_MSG);
		error = EINVAL;
		goto release;
	}

	/*
	 * Hack alert!
	 * We look into the message and if it mkpeers a node of unknown type, we
	 * try to load it. We need to do this now, in syscall thread, because if
	 * message gets queued and applied later we will get panic.
	 */
	if (msg->header.typecookie == NGM_GENERIC_COOKIE &&
	    msg->header.cmd == NGM_MKPEER) {
		struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
		struct ng_type *type;

		if ((type = ng_findtype(mkp->type)) == NULL) {
			char filename[NG_TYPESIZ + 3];
			linker_file_t fileid;

			if (!linker_api_available()) {
				error = ENXIO;
				goto done;
			}

			/* Not found, try to load it as a loadable module. */
			ksnprintf(filename, sizeof(filename), "ng_%s.ko",
			    mkp->type);
			error = linker_load_file(filename, &fileid);
			if (error != 0) {
				kfree(msg, M_NETGRAPH_MSG);
				goto release;
			}

			/* See if type has been loaded successfully. */
			if ((type = ng_findtype(mkp->type)) == NULL) {
				kfree(msg, M_NETGRAPH_MSG);
				(void)linker_file_unload(fileid);
				error =  ENXIO;
				goto release;
			}
		}
	}

	item = ng_package_msg(msg, NG_WAITOK);
	if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0))
	    != 0) {
#ifdef TRACE_MESSAGES
		kprintf("ng_address_path: errx=%d\n", error);
#endif
		goto release;
	}

#ifdef TRACE_MESSAGES
	kprintf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n",
		item->el_dest->nd_ID,
		msg->header.typecookie,
		msg->header.cmd,
		msg->header.cmdstr,
		msg->header.flags,
		msg->header.token,
		item->el_dest->nd_type->name);
#endif
	SAVE_LINE(item);

	/*
	 * We do not want the user thread to return from syscall until the
	 * item is processed by destination node.  We register callback
	 * on the item, which will reply to the user thread when item
	 * was applied.
	 */
	apply = ng_alloc_apply();
	bzero(apply, sizeof(*apply));
	apply->apply = ng_socket_item_applied;
	apply->context = &netmsg->send.base.lmsg;
	item->apply = apply;

	error = ng_snd_item(item, NG_PROGRESS);

release:
	if (path != NULL)
		kfree(path, M_NETGRAPH_PATH);
	if (control != NULL)
		m_freem(control);
	if (m != NULL)
		m_freem(m);
done:
	if (error != EINPROGRESS)
		lwkt_replymsg(&netmsg->send.base.lmsg, error);
}
Ejemplo n.º 23
0
/*
 * IPsec input callback, called by the transform callback. Takes care of
 * filtering and other sanity checks on the processed packet.
 */
int
ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff,
    struct m_tag *mt)
{
	int af, sproto;
	u_char prot;

#if NBPFILTER > 0
	struct ifnet *encif;
#endif

#ifdef INET
	struct ip *ip, ipn;
#endif /* INET */

#ifdef INET6
	struct ip6_hdr *ip6, ip6n;
#endif /* INET6 */
	struct m_tag *mtag;
	struct tdb_ident *tdbi;

	af = tdbp->tdb_dst.sa.sa_family;
	sproto = tdbp->tdb_sproto;

	tdbp->tdb_last_used = time_second;

	/* Sanity check */
	if (m == NULL) {
		/* The called routine will print a message if necessary */
		IPSEC_ISTAT(espstat.esps_badkcr, ahstat.ahs_badkcr,
		    ipcompstat.ipcomps_badkcr);
		return EINVAL;
	}

#ifdef INET
	/* Fix IPv4 header */
	if (af == AF_INET) {
		if ((m->m_len < skip) && ((m = m_pullup(m, skip)) == NULL)) {
			DPRINTF(("ipsec_common_input_cb(): processing failed "
			    "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
			    ntohl(tdbp->tdb_spi)));
			IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
			    ipcompstat.ipcomps_hdrops);
			return ENOBUFS;
		}

		ip = mtod(m, struct ip *);
		ip->ip_len = htons(m->m_pkthdr.len);
		ip->ip_sum = 0;
		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
		prot = ip->ip_p;

		/* IP-in-IP encapsulation */
		if (prot == IPPROTO_IPIP) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ipn will now contain the inner IPv4 header */
			m_copydata(m, skip, sizeof(struct ip),
			    (caddr_t) &ipn);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
			    tdbp->tdb_proxy.sin.sin_addr.s_addr !=
			    INADDR_ANY &&
			    ipn.ip_src.s_addr !=
			    tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET, &ipn.ip_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}

#ifdef INET6
		/* IPv6-in-IP encapsulation. */
		if (prot == IPPROTO_IPV6) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ip6n will now contain the inner IPv6 header. */
			m_copydata(m, skip, sizeof(struct ip6_hdr),
			    (caddr_t) &ip6n);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
			    !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
			    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
				&tdbp->tdb_proxy.sin6.sin6_addr)) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET6_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET6, &ip6n.ip6_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
#endif /* INET6 */
	}
#endif /* INET */

#ifdef INET6
	/* Fix IPv6 header */
	if (af == AF_INET6)
	{
		if (m->m_len < sizeof(struct ip6_hdr) &&
		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {

			DPRINTF(("ipsec_common_input_cb(): processing failed "
			    "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
			    ntohl(tdbp->tdb_spi)));

			IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
			    ipcompstat.ipcomps_hdrops);
			return EACCES;
		}

		ip6 = mtod(m, struct ip6_hdr *);
		ip6->ip6_plen = htons(m->m_pkthdr.len - skip);

		/* Save protocol */
		m_copydata(m, protoff, 1, (caddr_t) &prot);

#ifdef INET
		/* IP-in-IP encapsulation */
		if (prot == IPPROTO_IPIP) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ipn will now contain the inner IPv4 header */
			m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
			    tdbp->tdb_proxy.sin.sin_addr.s_addr !=
			    INADDR_ANY &&
			    ipn.ip_src.s_addr !=
				tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET, &ipn.ip_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
#endif /* INET */

		/* IPv6-in-IP encapsulation */
		if (prot == IPPROTO_IPV6) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ip6n will now contain the inner IPv6 header. */
			m_copydata(m, skip, sizeof(struct ip6_hdr),
			    (caddr_t) &ip6n);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
			    !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
			    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
				&tdbp->tdb_proxy.sin6.sin6_addr)) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET6_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET6, &ip6n.ip6_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
	}
#endif /* INET6 */

	/*
	 * Fix TCP/UDP checksum of UDP encapsulated transport mode ESP packet.
	 * (RFC3948 3.1.2)
	 */
	if ((af == AF_INET || af == AF_INET6) &&
	    (tdbp->tdb_flags & TDBF_UDPENCAP) &&
	    (tdbp->tdb_flags & TDBF_TUNNELING) == 0) {
		u_int16_t cksum;

		switch (prot) {
		case IPPROTO_UDP:
			if (m->m_pkthdr.len < skip + sizeof(struct udphdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			cksum = 0;
			m_copyback(m, skip + offsetof(struct udphdr, uh_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
#ifdef INET6
			if (af == AF_INET6) {
				cksum = in6_cksum(m, IPPROTO_UDP, skip,
				    m->m_pkthdr.len - skip);
				m_copyback(m, skip + offsetof(struct udphdr,
				    uh_sum), sizeof(cksum), &cksum, M_NOWAIT);
			}
#endif
			break;
		case IPPROTO_TCP:
			if (m->m_pkthdr.len < skip + sizeof(struct tcphdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			cksum = 0;
			m_copyback(m, skip + offsetof(struct tcphdr, th_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
			if (af == AF_INET)
				cksum = in4_cksum(m, IPPROTO_TCP, skip,
				    m->m_pkthdr.len - skip);
#ifdef INET6
			else if (af == AF_INET6)
				cksum = in6_cksum(m, IPPROTO_TCP, skip,
				    m->m_pkthdr.len - skip);
#endif
			m_copyback(m, skip + offsetof(struct tcphdr, th_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
			break;
		}
Ejemplo n.º 24
0
/*
 * ipsec_common_input() gets called when we receive an IPsec-protected packet
 * in IPv4 or IPv6. All it does is find the right TDB and call the appropriate
 * transform. The callback takes care of further processing (like ingress
 * filtering).
 */
int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto,
    int udpencap)
{
#define IPSEC_ISTAT(x,y,z) (sproto == IPPROTO_ESP ? (x)++ : \
			    sproto == IPPROTO_AH ? (y)++ : (z)++)

	union sockaddr_union dst_address;
	struct timeval tv;
	struct tdb *tdbp;
	struct ifnet *encif;
	u_int32_t spi;
	u_int16_t cpi;
	int s, error;

	IPSEC_ISTAT(espstat.esps_input, ahstat.ahs_input,
	    ipcompstat.ipcomps_input);

	if (m == 0) {
		DPRINTF(("ipsec_common_input(): NULL packet received\n"));
		IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
		    ipcompstat.ipcomps_hdrops);
		return EINVAL;
	}

	if ((sproto == IPPROTO_ESP && !esp_enable) ||
	    (sproto == IPPROTO_AH && !ah_enable) ||
#if NPF > 0
	    (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) ||
#endif
	    (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
		switch (af) {
#ifdef INET
		case AF_INET:
			rip_input(m, skip, sproto);
			break;
#endif /* INET */
#ifdef INET6
		case AF_INET6:
			rip6_input(&m, &skip, sproto);
			break;
#endif /* INET6 */
		default:
			DPRINTF(("ipsec_common_input(): unsupported protocol "
			    "family %d\n", af));
			m_freem(m);
			IPSEC_ISTAT(espstat.esps_nopf, ahstat.ahs_nopf,
			    ipcompstat.ipcomps_nopf);
			return EPFNOSUPPORT;
		}
		return 0;
	}
	if ((sproto == IPPROTO_IPCOMP) && (m->m_flags & M_COMP)) {
		m_freem(m);
		ipcompstat.ipcomps_pdrops++;
		DPRINTF(("ipsec_common_input(): repeated decompression\n"));
		return EINVAL;
	}

	if (m->m_pkthdr.len - skip < 2 * sizeof(u_int32_t)) {
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
		    ipcompstat.ipcomps_hdrops);
		DPRINTF(("ipsec_common_input(): packet too small\n"));
		return EINVAL;
	}

	/* Retrieve the SPI from the relevant IPsec header */
	if (sproto == IPPROTO_ESP)
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
	else if (sproto == IPPROTO_AH)
		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
		    (caddr_t) &spi);
	else if (sproto == IPPROTO_IPCOMP) {
		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
		    (caddr_t) &cpi);
		spi = ntohl(htons(cpi));
	}

	/*
	 * Find tunnel control block and (indirectly) call the appropriate
	 * kernel crypto routine. The resulting mbuf chain is a valid
	 * IP packet ready to go through input processing.
	 */

	memset(&dst_address, 0, sizeof(dst_address));
	dst_address.sa.sa_family = af;

	switch (af) {
#ifdef INET
	case AF_INET:
		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
		m_copydata(m, offsetof(struct ip, ip_dst),
		    sizeof(struct in_addr),
		    (caddr_t) &(dst_address.sin.sin_addr));
		break;
#endif /* INET */

#ifdef INET6
	case AF_INET6:
		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
		    sizeof(struct in6_addr),
		    (caddr_t) &(dst_address.sin6.sin6_addr));
		in6_recoverscope(&dst_address.sin6, &dst_address.sin6.sin6_addr,
		    NULL);
		break;
#endif /* INET6 */

	default:
		DPRINTF(("ipsec_common_input(): unsupported protocol "
		    "family %d\n", af));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_nopf, ahstat.ahs_nopf,
		    ipcompstat.ipcomps_nopf);
		return EPFNOSUPPORT;
	}

	s = splsoftnet();
	tdbp = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
	    spi, &dst_address, sproto);
	if (tdbp == NULL) {
		splx(s);
		DPRINTF(("ipsec_common_input(): could not find SA for "
		    "packet to %s, spi %08x\n",
		    ipsp_address(dst_address), ntohl(spi)));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_notdb, ahstat.ahs_notdb,
		    ipcompstat.ipcomps_notdb);
		return ENOENT;
	}

	if (tdbp->tdb_flags & TDBF_INVALID) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use invalid SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_invalid, ahstat.ahs_invalid,
		    ipcompstat.ipcomps_invalid);
		return EINVAL;
	}

	if (udpencap && !(tdbp->tdb_flags & TDBF_UDPENCAP)) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use non-udpencap SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		espstat.esps_udpinval++;
		return EINVAL;
	}

	if (tdbp->tdb_xform == NULL) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use uninitialized SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_noxform, ahstat.ahs_noxform,
		    ipcompstat.ipcomps_noxform);
		return ENXIO;
	}

	if (sproto != IPPROTO_IPCOMP) {
		if ((encif = enc_getif(tdbp->tdb_rdomain,
		    tdbp->tdb_tap)) == NULL) {
			splx(s);
			DPRINTF(("ipsec_common_input(): "
			    "no enc%u interface for SA %s/%08x/%u\n",
			    tdbp->tdb_tap, ipsp_address(dst_address),
			    ntohl(spi), tdbp->tdb_sproto));
			m_freem(m);

			IPSEC_ISTAT(espstat.esps_pdrops,
			    ahstat.ahs_pdrops,
			    ipcompstat.ipcomps_pdrops);
			return EACCES;
		}

		/* XXX This conflicts with the scoped nature of IPv6 */
		m->m_pkthdr.rcvif = encif;
	}

	/* Register first use, setup expiration timer. */
	if (tdbp->tdb_first_use == 0) {
		tdbp->tdb_first_use = time_second;

		tv.tv_usec = 0;

		tv.tv_sec = tdbp->tdb_exp_first_use + tdbp->tdb_first_use;
		if (tdbp->tdb_flags & TDBF_FIRSTUSE)
			timeout_add(&tdbp->tdb_first_tmo, hzto(&tv));

		tv.tv_sec = tdbp->tdb_first_use + tdbp->tdb_soft_first_use;
		if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE)
			timeout_add(&tdbp->tdb_sfirst_tmo, hzto(&tv));
	}

	/*
	 * Call appropriate transform and return -- callback takes care of
	 * everything else.
	 */
	error = (*(tdbp->tdb_xform->xf_input))(m, tdbp, skip, protoff);
	splx(s);
	return error;
}
Ejemplo n.º 25
0
/*
 * Synchronize an ISA DMA map.
 */
void
isadma_bounce_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    bus_size_t len, int ops)
{
	struct isadma_bounce_cookie *cookie = map->_dm_cookie;

	/*
	 * Mixing PRE and POST operations is not allowed.
	 */
	if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
	    (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
		panic("isadma_bounce_dmamap_sync: mix PRE and POST");

#ifdef DIAGNOSTIC
	if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
		if (offset >= map->dm_mapsize)
			panic("isadma_bounce_dmamap_sync: bad offset");
		if (len == 0 || (offset + len) > map->dm_mapsize)
			panic("isadma_bounce_dmamap_sync: bad length");
	}
#endif

	/*
	 * If we're not bouncing, just do the normal sync operation
	 * and return.
	 */
	if ((cookie->id_flags & ID_IS_BOUNCING) == 0) {
		_bus_dmamap_sync(t, map, offset, len, ops);
		return;
	}

	/*
	 * Flush data cache for PREREAD.  This has the side-effect
	 * of invalidating the cache.  Done at PREREAD since it
	 * causes the cache line(s) to be written back to memory.
	 *
	 * Copy the original buffer to the bounce buffer and flush
	 * the data cache for PREWRITE, so that the contents
	 * of the data buffer in memory reflect reality.
	 *
	 * Copy the bounce buffer to the original buffer in POSTREAD.
	 */

	switch (cookie->id_buftype) {
	case ID_BUFTYPE_LINEAR:
		/*
		 * Nothing to do for pre-read.
		 */

		if (ops & BUS_DMASYNC_PREWRITE) {
			/*
			 * Copy the caller's buffer to the bounce buffer.
			 */
			memcpy((char *)cookie->id_bouncebuf + offset,
			    (char *)cookie->id_origbuf + offset, len);
			wbflush();
		}

		if (ops & BUS_DMASYNC_POSTREAD) {
			/*
			 * Copy the bounce buffer to the caller's buffer.
			 */
			memcpy((char *)cookie->id_origbuf + offset,
			    (char *)cookie->id_bouncebuf + offset, len);
		}

		/*
		 * Nothing to do for post-write.
		 */
		break;

	case ID_BUFTYPE_MBUF:
	    {
		struct mbuf *m, *m0 = cookie->id_origbuf;
		bus_size_t minlen, moff;

		/*
		 * Nothing to do for pre-read.
		 */

		if (ops & BUS_DMASYNC_PREWRITE) {
			/*
			 * Copy the caller's buffer to the bounce buffer.
			 */
			m_copydata(m0, offset, len,
			    (char *)cookie->id_bouncebuf + offset);
		}

		if (ops & BUS_DMASYNC_POSTREAD) {
			/*
			 * Copy the bounce buffer to the caller's buffer.
			 */
			for (moff = offset, m = m0; m != NULL && len != 0;
			     m = m->m_next) {
				/* Find the beginning mbuf. */
				if (moff >= m->m_len) {
					moff -= m->m_len;
					continue;
				}

				/*
				 * Now at the first mbuf to sync; nail
				 * each one until we have exhausted the
				 * length.
				 */
				minlen = len < m->m_len - moff ?
				    len : m->m_len - moff;

				memcpy(mtod(m, caddr_t) + moff,
				    (char *)cookie->id_bouncebuf + offset,
				    minlen);

				moff = 0;
				len -= minlen;
				offset += minlen;
			}
		}

		/*
		 * Nothing to do for post-write.
		 */
		break;
	    }

	case ID_BUFTYPE_UIO:
		panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_UIO");
		break;

	case ID_BUFTYPE_RAW:
		panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_RAW");
		break;

	case ID_BUFTYPE_INVALID:
		panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_INVALID");
		break;

	default:
		printf("unknown buffer type %d\n", cookie->id_buftype);
		panic("isadma_bounce_dmamap_sync");
	}

	/* Drain the write buffer. */
	wbflush();

	/* XXXJRT */
	if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE))
		mips_dcache_wbinv_range((vaddr_t)cookie->id_bouncebuf + offset,
		    len);
}
Ejemplo n.º 26
0
/*
 * Massage IPv4/IPv6 headers for AH processing.
 */
int
ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
{
	struct mbuf *m = *m0;
	unsigned char *ptr;
	int off, count;

#ifdef INET
	struct ip *ip;
#endif /* INET */

#ifdef INET6
	struct ip6_ext *ip6e;
	struct ip6_hdr ip6;
	int ad, alloc, nxt;
#endif /* INET6 */

	switch (proto) {
#ifdef INET
	case AF_INET:
		/*
		 * This is the least painful way of dealing with IPv4 header
		 * and option processing -- just make sure they're in
		 * contiguous memory.
		 */
		*m0 = m = m_pullup(m, skip);
		if (m == NULL) {
			DPRINTF(("ah_massage_headers(): m_pullup() failed\n"));
			ahstat.ahs_hdrops++;
			return ENOBUFS;
		}

		/* Fix the IP header */
		ip = mtod(m, struct ip *);
		ip->ip_tos = 0;
		ip->ip_ttl = 0;
		ip->ip_sum = 0;

		/*
		 * On input, fix ip_len which has been byte-swapped
		 * at ip_input().
		 */
		if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK)
			ip->ip_off &= htons(IP_DF);
		else
			ip->ip_off = 0;

		ptr = mtod(m, unsigned char *) + sizeof(struct ip);

		/* IPv4 option processing */
		for (off = sizeof(struct ip); off < skip;) {
			if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP ||
			    off + 1 < skip)
				;
			else {
				DPRINTF(("ah_massage_headers(): illegal IPv4 "
				    "option length for option %d\n",
				    ptr[off]));

				ahstat.ahs_hdrops++;
				m_freem(m);
				return EINVAL;
			}

			switch (ptr[off]) {
			case IPOPT_EOL:
				off = skip;  /* End the loop. */
				break;

			case IPOPT_NOP:
				off++;
				break;

			case IPOPT_SECURITY:	/* 0x82 */
			case 0x85:	/* Extended security. */
			case 0x86:	/* Commercial security. */
			case 0x94:	/* Router alert */
			case 0x95:	/* RFC1770 */
				/* Sanity check for option length. */
				if (ptr[off + 1] < 2) {
					DPRINTF(("ah_massage_headers(): "
					    "illegal IPv4 option length for "
					    "option %d\n", ptr[off]));

					ahstat.ahs_hdrops++;
					m_freem(m);
					return EINVAL;
				}

				off += ptr[off + 1];
				break;

			case IPOPT_LSRR:
			case IPOPT_SSRR:
				/* Sanity check for option length. */
				if (ptr[off + 1] < 2) {
					DPRINTF(("ah_massage_headers(): "
					    "illegal IPv4 option length for "
					    "option %d\n", ptr[off]));

					ahstat.ahs_hdrops++;
					m_freem(m);
					return EINVAL;
				}

				/*
				 * On output, if we have either of the
				 * source routing options, we should
				 * swap the destination address of the
				 * IP header with the last address
				 * specified in the option, as that is
				 * what the destination's IP header
				 * will look like.
				 */
				if (out)
					bcopy(ptr + off + ptr[off + 1] -
					    sizeof(struct in_addr),
					    &(ip->ip_dst), sizeof(struct in_addr));

				/* FALLTHROUGH */
			default:
				/* Sanity check for option length. */
				if (ptr[off + 1] < 2) {
					DPRINTF(("ah_massage_headers(): "
					    "illegal IPv4 option length for "
					    "option %d\n", ptr[off]));
					ahstat.ahs_hdrops++;
					m_freem(m);
					return EINVAL;
				}

				/* Zeroize all other options. */
				count = ptr[off + 1];
				bcopy(ipseczeroes, ptr, count);
				off += count;
				break;
			}

			/* Sanity check. */
			if (off > skip)	{
				DPRINTF(("ah_massage_headers(): malformed "
				    "IPv4 options header\n"));

				ahstat.ahs_hdrops++;
				m_freem(m);
				return EINVAL;
			}
		}

		break;
#endif /* INET */

#ifdef INET6
	case AF_INET6:  /* Ugly... */
		/* Copy and "cook" the IPv6 header. */
		m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6);

		/* We don't do IPv6 Jumbograms. */
		if (ip6.ip6_plen == 0) {
			DPRINTF(("ah_massage_headers(): unsupported IPv6 "
			    "jumbogram"));
			ahstat.ahs_hdrops++;
			m_freem(m);
			return EMSGSIZE;
		}

		ip6.ip6_flow = 0;
		ip6.ip6_hlim = 0;
		ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
		ip6.ip6_vfc |= IPV6_VERSION;

		/* Scoped address handling. */
		if (IN6_IS_SCOPE_EMBED(&ip6.ip6_src))
			ip6.ip6_src.s6_addr16[1] = 0;
		if (IN6_IS_SCOPE_EMBED(&ip6.ip6_dst))
			ip6.ip6_dst.s6_addr16[1] = 0;

		/* Done with IPv6 header. */
		m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6, M_NOWAIT);

		/* Let's deal with the remaining headers (if any). */
		if (skip - sizeof(struct ip6_hdr) > 0) {
			if (m->m_len <= skip) {
				ptr = malloc(skip - sizeof(struct ip6_hdr),
				    M_XDATA, M_NOWAIT);
				if (ptr == NULL) {
					DPRINTF(("ah_massage_headers(): failed to allocate memory for IPv6 headers\n"));
					ahstat.ahs_hdrops++;
					m_freem(m);
					return ENOBUFS;
				}

				/*
				 * Copy all the protocol headers after
				 * the IPv6 header.
				 */
				m_copydata(m, sizeof(struct ip6_hdr),
				    skip - sizeof(struct ip6_hdr), ptr);
				alloc = 1;
			} else {
				/* No need to allocate memory. */
				ptr = mtod(m, unsigned char *) +
				    sizeof(struct ip6_hdr);
				alloc = 0;
			}
		} else
			break;

		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */

		for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
			switch (nxt) {
			case IPPROTO_HOPOPTS:
			case IPPROTO_DSTOPTS:
				ip6e = (struct ip6_ext *) (ptr + off);

				/*
				 * Process the mutable/immutable
				 * options -- borrows heavily from the
				 * KAME code.
				 */
				for (count = off + sizeof(struct ip6_ext);
				     count < off + ((ip6e->ip6e_len + 1) << 3);) {
					if (ptr[count] == IP6OPT_PAD1) {
						count++;
						continue; /* Skip padding. */
					}

					/* Sanity check. */
					if (count > off +
					    ((ip6e->ip6e_len + 1) << 3)) {
						ahstat.ahs_hdrops++;
						m_freem(m);

						/* Free, if we allocated. */
						if (alloc)
							free(ptr, M_XDATA);
						return EINVAL;
					}

					ad = ptr[count + 1];

					/* If mutable option, zeroize. */
					if (ptr[count] & IP6OPT_MUTABLE)
						bcopy(ipseczeroes, ptr + count,
						    ptr[count + 1]);

					count += ad;

					/* Sanity check. */
					if (count >
					    skip - sizeof(struct ip6_hdr)) {
						ahstat.ahs_hdrops++;
						m_freem(m);

						/* Free, if we allocated. */
						if (alloc)
							free(ptr, M_XDATA);
						return EINVAL;
					}
				}

				/* Advance. */
				off += ((ip6e->ip6e_len + 1) << 3);
				nxt = ip6e->ip6e_nxt;
				break;

			case IPPROTO_ROUTING:
				/*
				 * Always include routing headers in
				 * computation.
				 */
			    {
				struct ip6_rthdr *rh;

				ip6e = (struct ip6_ext *) (ptr + off);
				rh = (struct ip6_rthdr *)(ptr + off);
				/*
				 * must adjust content to make it look like
				 * its final form (as seen at the final
				 * destination).
				 * we only know how to massage type 0 routing
				 * header.
				 */
				if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) {
					struct ip6_rthdr0 *rh0;
					struct in6_addr *addr, finaldst;
					int i;

					rh0 = (struct ip6_rthdr0 *)rh;
					addr = (struct in6_addr *)(rh0 + 1);

					for (i = 0; i < rh0->ip6r0_segleft; i++)
						if (IN6_IS_SCOPE_EMBED(&addr[i]))
							addr[i].s6_addr16[1] = 0;

					finaldst = addr[rh0->ip6r0_segleft - 1];
					memmove(&addr[1], &addr[0],
					    sizeof(struct in6_addr) *
					    (rh0->ip6r0_segleft - 1));

					m_copydata(m, 0, sizeof(ip6),
					    (caddr_t)&ip6);
					addr[0] = ip6.ip6_dst;
					ip6.ip6_dst = finaldst;
					m_copyback(m, 0, sizeof(ip6), &ip6,
					    M_NOWAIT);

					rh0->ip6r0_segleft = 0;
				}

				/* advance */
				off += ((ip6e->ip6e_len + 1) << 3);
				nxt = ip6e->ip6e_nxt;
				break;
			    }

			default:
				DPRINTF(("ah_massage_headers(): unexpected "
				    "IPv6 header type %d\n", off));
				if (alloc)
					free(ptr, M_XDATA);
				ahstat.ahs_hdrops++;
				m_freem(m);
				return EINVAL;
			}
		}

		/* Copyback and free, if we allocated. */
		if (alloc) {
			m_copyback(m, sizeof(struct ip6_hdr),
			    skip - sizeof(struct ip6_hdr), ptr, M_NOWAIT);
			free(ptr, M_XDATA);
		}

		break;
#endif /* INET6 */
	}
Ejemplo n.º 27
0
/*
 * Copy data from m to n, where n cannot fit all the data we might
 * want from m.
 *
 * Prioritize data like this:
 * 1. TCP header
 * 2. IP header
 * 3. Data
 */
static void
tcp_pcap_copy_bestfit(struct tcphdr *th, struct mbuf *m, struct mbuf *n)
{
	struct mbuf *m_cur = m;
	int bytes_to_copy=0, trailing_data, skip=0, tcp_off;

	/* Below, we assume these will be non-NULL. */
	KASSERT(th, ("%s: called with th == NULL", __func__));
	KASSERT(m, ("%s: called with m == NULL", __func__));
	KASSERT(n, ("%s: called with n == NULL", __func__));

	/* We assume this initialization occurred elsewhere. */
	KASSERT(n->m_len == 0, ("%s: called with n->m_len=%d (expected 0)",
		__func__, n->m_len));
	KASSERT(n->m_data == M_START(n),
		("%s: called with n->m_data != M_START(n)", __func__));

	/*
	 * Calculate the size of the TCP header. We use this often
	 * enough that it is worth just calculating at the start.
	 */
	tcp_off = th->th_off << 2;

	/* Trim off leading empty mbufs. */
	while (m && m->m_len == 0)
		m = m->m_next;

	if (m) {
		m_cur = m;
	}
	else {
		/*
		 * No data? Highly unusual. We would expect to at
		 * least see a TCP header in the mbuf.
		 * As we have a pointer to the TCP header, I guess
		 * we should just copy that. (???)
		 */
fallback:
		bytes_to_copy = tcp_off;
		if (bytes_to_copy > M_SIZE(n))
			bytes_to_copy = M_SIZE(n);
		bcopy(th, n->m_data, bytes_to_copy);
		n->m_len = bytes_to_copy;
		return;
	}

	/*
	 * Find TCP header. Record the total number of bytes up to,
	 * and including, the TCP header.
	 */
	while (m_cur) {
		if ((caddr_t) th >= (caddr_t) m_cur->m_data &&
			(caddr_t) th < (caddr_t) (m_cur->m_data + m_cur->m_len))
			break;
		bytes_to_copy += m_cur->m_len;
		m_cur = m_cur->m_next;
	}
	if (m_cur)
		bytes_to_copy += (caddr_t) th - (caddr_t) m_cur->m_data;
	else
		goto fallback;
	bytes_to_copy += tcp_off;

	/*
	 * If we already want to copy more bytes than we can hold
	 * in the destination mbuf, skip leading bytes and copy
	 * what we can.
	 *
	 * Otherwise, consider trailing data.
	 */
	if (bytes_to_copy > M_SIZE(n)) {
		skip  = bytes_to_copy - M_SIZE(n);
		bytes_to_copy = M_SIZE(n);
	}
	else {
		/*
		 * Determine how much trailing data is in the chain.
		 * We start with the length of this mbuf (the one
		 * containing th) and subtract the size of the TCP
		 * header (tcp_off) and the size of the data prior
		 * to th (th - m_cur->m_data).
		 *
		 * This *should not* be negative, as the TCP code
		 * should put the whole TCP header in a single
		 * mbuf. But, it isn't a problem if it is. We will
		 * simple work off our negative balance as we look
		 * at subsequent mbufs.
		 */
		trailing_data = m_cur->m_len - tcp_off;
		trailing_data -= (caddr_t) th - (caddr_t) m_cur->m_data;
		m_cur = m_cur->m_next;
		while (m_cur) {
			trailing_data += m_cur->m_len;
			m_cur = m_cur->m_next;
		}
		if ((bytes_to_copy + trailing_data) > M_SIZE(n))
			bytes_to_copy = M_SIZE(n);
		else
			bytes_to_copy += trailing_data;
	}

	m_copydata(m, skip, bytes_to_copy, n->m_data);
	n->m_len = bytes_to_copy;
}
Ejemplo n.º 28
0
void
udp_input(struct mbuf *m, ...)
{
	struct ip *ip;
	struct udphdr *uh;
	struct inpcb *inp = NULL;
	struct mbuf *opts = NULL;
	struct ip save_ip;
	int iphlen, len;
	va_list ap;
	u_int16_t savesum;
	union {
		struct sockaddr sa;
		struct sockaddr_in sin;
#ifdef INET6
		struct sockaddr_in6 sin6;
#endif /* INET6 */
	} srcsa, dstsa;
#ifdef INET6
	struct ip6_hdr *ip6;
#endif /* INET6 */
#ifdef IPSEC
	struct m_tag *mtag;
	struct tdb_ident *tdbi;
	struct tdb *tdb;
	int error, s;
#endif /* IPSEC */

	va_start(ap, m);
	iphlen = va_arg(ap, int);
	va_end(ap);

	udpstat.udps_ipackets++;

	switch (mtod(m, struct ip *)->ip_v) {
	case 4:
		ip = mtod(m, struct ip *);
#ifdef INET6
		ip6 = NULL;
#endif /* INET6 */
		srcsa.sa.sa_family = AF_INET;
		break;
#ifdef INET6
	case 6:
		ip = NULL;
		ip6 = mtod(m, struct ip6_hdr *);
		srcsa.sa.sa_family = AF_INET6;
		break;
#endif /* INET6 */
	default:
		goto bad;
	}

	IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
	if (!uh) {
		udpstat.udps_hdrops++;
		return;
	}

	/* Check for illegal destination port 0 */
	if (uh->uh_dport == 0) {
		udpstat.udps_noport++;
		goto bad;
	}

	/*
	 * Make mbuf data length reflect UDP length.
	 * If not enough data to reflect UDP length, drop.
	 */
	len = ntohs((u_int16_t)uh->uh_ulen);
	if (ip) {
		if (m->m_pkthdr.len - iphlen != len) {
			if (len > (m->m_pkthdr.len - iphlen) ||
			    len < sizeof(struct udphdr)) {
				udpstat.udps_badlen++;
				goto bad;
			}
			m_adj(m, len - (m->m_pkthdr.len - iphlen));
		}
	}
#ifdef INET6
	else if (ip6) {
		/* jumbograms */
		if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff)
			len = m->m_pkthdr.len - iphlen;
		if (len != m->m_pkthdr.len - iphlen) {
			udpstat.udps_badlen++;
			goto bad;
		}
	}
#endif
	else /* shouldn't happen */
		goto bad;

	/*
	 * Save a copy of the IP header in case we want restore it
	 * for sending an ICMP error message in response.
	 */
	if (ip)
		save_ip = *ip;

	/*
	 * Checksum extended UDP header and data.
	 * from W.R.Stevens: check incoming udp cksums even if
	 *	udpcksum is not set.
	 */
	savesum = uh->uh_sum;
#ifdef INET6
	if (ip6) {
		/* Be proactive about malicious use of IPv4 mapped address */
		if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
		    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
			/* XXX stat */
			goto bad;
		}

		/*
		 * In IPv6, the UDP checksum is ALWAYS used.
		 */
		if (uh->uh_sum == 0) {
			udpstat.udps_nosum++;
			goto bad;
		}
		if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
			if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
				udpstat.udps_badsum++;
				udpstat.udps_inhwcsum++;
				goto bad;
			}

			if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
			    iphlen, len))) {
				udpstat.udps_badsum++;
				goto bad;
			}
		} else {
			m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK;
			udpstat.udps_inhwcsum++;
		}
	} else
#endif /* INET6 */
	if (uh->uh_sum) {
		if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
			if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
				udpstat.udps_badsum++;
				udpstat.udps_inhwcsum++;
				m_freem(m);
				return;
			}

			if ((uh->uh_sum = in4_cksum(m, IPPROTO_UDP,
			    iphlen, len))) {
				udpstat.udps_badsum++;
				m_freem(m);
				return;
			}
		} else {
			m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK;
			udpstat.udps_inhwcsum++;
		}
	} else
		udpstat.udps_nosum++;

#ifdef IPSEC
	if (udpencap_enable && udpencap_port &&
	    uh->uh_dport == htons(udpencap_port)) {
		u_int32_t spi;
		int skip = iphlen + sizeof(struct udphdr);

		if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) {
			/* packet too short */
			m_freem(m);
			return;
		}
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
		/*
		 * decapsulate if the SPI is not zero, otherwise pass
		 * to userland
		 */
		if (spi != 0) {
			if ((m = m_pullup2(m, skip)) == NULL) {
				udpstat.udps_hdrops++;
				return;
			}

			/* remove the UDP header */
			bcopy(mtod(m, u_char *),
			    mtod(m, u_char *) + sizeof(struct udphdr), iphlen);
			m_adj(m, sizeof(struct udphdr));
			skip -= sizeof(struct udphdr);

			espstat.esps_udpencin++;
			ipsec_common_input(m, skip, offsetof(struct ip, ip_p),
			    srcsa.sa.sa_family, IPPROTO_ESP, 1);
			return;
		}
	}
Ejemplo n.º 29
0
static void
if_netmap_send(void *arg)
{
	struct mbuf *m;
	struct if_netmap_softc *sc = (struct if_netmap_softc *)arg;
	struct ifnet *ifp = sc->ifp;
	struct uhi_pollfd pfd;
	uint32_t avail;
	uint32_t cur;
	u_int pktlen;
	int rv;
	int done;
	int pkts_sent;

	if (sc->cfg->cpu >= 0)
		sched_bind(sc->tx_thread.thr, sc->cfg->cpu);

	rv = if_netmap_txsync(sc->nm_host_ctx, NULL, NULL);
	if (rv == -1) {
		printf("could not sync tx descriptors before transmit\n");
	}

	avail = if_netmap_txavail(sc->nm_host_ctx);

	sc->tx_thread.last_stop_check = ticks;
	done = 0;
	pkts_sent = 0;
	do {
		mtx_lock(&sc->tx_lock);
		sc->tx_pkts_to_send -= pkts_sent;
		while ((sc->tx_pkts_to_send == 0) && !done)
			if (EWOULDBLOCK == cv_timedwait(&sc->tx_cv, &sc->tx_lock, sc->stop_check_ticks))
				done = if_netmap_stoppable_thread_check(&sc->tx_thread);
		mtx_unlock(&sc->tx_lock);
	
		if (done)
			break;

		pkts_sent = 0;

		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
		while (m) {
			while (0 == avail && !done) {
				memset(&pfd, 0, sizeof(pfd));

				pfd.fd = sc->fd;
				pfd.events = UHI_POLLOUT;
				
				rv = uhi_poll(&pfd, 1, IF_NETMAP_THREAD_STOP_CHECK_MS);
				if (rv == 0)
					done = if_netmap_stoppable_thread_check(&sc->tx_thread);	
				else if (rv == -1)
					printf("error from poll for transmit\n");
					
				avail = if_netmap_txavail(sc->nm_host_ctx);
			}

			if (ticks - sc->tx_thread.last_stop_check >= sc->stop_check_ticks)
				done = if_netmap_stoppable_thread_check(&sc->tx_thread);

			if (done)
				break;

			cur = if_netmap_txcur(sc->nm_host_ctx);

			while (m && avail) {
				ifp->if_ocopies++;
				ifp->if_opackets++;

				avail--;
				pkts_sent++;

				pktlen = m_length(m, NULL);

				m_copydata(m, 0, pktlen,
					   if_netmap_txslot(sc->nm_host_ctx, &cur, pktlen)); 
				m_freem(m);

				IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
			}

			rv = if_netmap_txsync(sc->nm_host_ctx, &avail, &cur);
			if (rv == -1) {
				printf("could not sync tx descriptors after transmit\n");
			}
			avail = if_netmap_txavail(sc->nm_host_ctx);
		}

	} while (!done);

	if_netmap_stoppable_thread_done(&sc->tx_thread);
}
Ejemplo n.º 30
0
/*
 * ESP input callback from the crypto driver.
 */
static int
esp_input_cb(struct cryptop *crp)
{
	char buf[128];
	u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN];
	int hlen, skip, protoff, error, alen;
	struct mbuf *m;
	struct cryptodesc *crd;
	struct auth_hash *esph;
	struct enc_xform *espx;
	struct tdb_crypto *tc;
	struct secasvar *sav;
	struct secasindex *saidx;
	caddr_t ptr;

	crd = crp->crp_desc;
	IPSEC_ASSERT(crd != NULL, ("null crypto descriptor!"));

	tc = (struct tdb_crypto *) crp->crp_opaque;
	IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
	skip = tc->tc_skip;
	protoff = tc->tc_protoff;
	m = (struct mbuf *) crp->crp_buf;

	sav = tc->tc_sav;
	IPSEC_ASSERT(sav != NULL, ("null SA!"));

	saidx = &sav->sah->saidx;
	IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
		saidx->dst.sa.sa_family == AF_INET6,
		("unexpected protocol family %u", saidx->dst.sa.sa_family));

	esph = sav->tdb_authalgxform;
	espx = sav->tdb_encalgxform;

	/* Check for crypto errors */
	if (crp->crp_etype) {
		/* Reset the session ID */
		if (sav->tdb_cryptoid != 0)
			sav->tdb_cryptoid = crp->crp_sid;

		if (crp->crp_etype == EAGAIN)
			return (crypto_dispatch(crp));

		ESPSTAT_INC(esps_noxform);
		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
		error = crp->crp_etype;
		goto bad;
	}

	/* Shouldn't happen... */
	if (m == NULL) {
		ESPSTAT_INC(esps_crypto);
		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
		error = EINVAL;
		goto bad;
	}
	ESPSTAT_INC(esps_hist[sav->alg_enc]);

	/* If authentication was performed, check now. */
	if (esph != NULL) {
		alen = xform_ah_authsize(esph);
		AHSTAT_INC(ahs_hist[sav->alg_auth]);
		/* Copy the authenticator from the packet */
		m_copydata(m, m->m_pkthdr.len - alen, alen, aalg);
		ptr = (caddr_t) (tc + 1);

		/* Verify authenticator */
		if (timingsafe_bcmp(ptr, aalg, alen) != 0) {
			DPRINTF(("%s: authentication hash mismatch for "
			    "packet in SA %s/%08lx\n", __func__,
			    ipsec_address(&saidx->dst, buf, sizeof(buf)),
			    (u_long) ntohl(sav->spi)));
			ESPSTAT_INC(esps_badauth);
			error = EACCES;
			goto bad;
		}

		/* Remove trailing authenticator */
		m_adj(m, -alen);
	}

	/* Release the crypto descriptors */
	free(tc, M_XDATA), tc = NULL;
	crypto_freereq(crp), crp = NULL;

	/*
	 * Packet is now decrypted.
	 */
	m->m_flags |= M_DECRYPTED;

	/*
	 * Update replay sequence number, if appropriate.
	 */
	if (sav->replay) {
		u_int32_t seq;

		m_copydata(m, skip + offsetof(struct newesp, esp_seq),
			   sizeof (seq), (caddr_t) &seq);
		if (ipsec_updatereplay(ntohl(seq), sav)) {
			DPRINTF(("%s: packet replay check for %s\n", __func__,
			    ipsec_logsastr(sav, buf, sizeof(buf))));
			ESPSTAT_INC(esps_replay);
			error = ENOBUFS;
			goto bad;
		}
	}