hyperv/hn: Reorganize RX path; mainly pull non-control code path up

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D8356
This commit is contained in:
Sepherosa Ziehau 2016-10-28 08:08:46 +00:00
parent 96a98cbf14
commit 91938ebba8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=308014
4 changed files with 364 additions and 379 deletions

View File

@ -166,6 +166,16 @@ __FBSDID("$FreeBSD$");
#define HN_EARLY_TXEOF_THRESH 8
#define HN_RXINFO_VLAN 0x0001
#define HN_RXINFO_CSUM 0x0002
#define HN_RXINFO_HASHINF 0x0004
#define HN_RXINFO_HASHVAL 0x0008
#define HN_RXINFO_ALL \
(HN_RXINFO_VLAN | \
HN_RXINFO_CSUM | \
HN_RXINFO_HASHINF | \
HN_RXINFO_HASHVAL)
struct hn_txdesc {
#ifndef HN_USE_TXDESC_BUFRING
SLIST_ENTRY(hn_txdesc) link;
@ -188,6 +198,17 @@ struct hn_txdesc {
#define HN_TXD_FLAG_ONLIST 0x1
#define HN_TXD_FLAG_DMAMAP 0x2
#define HN_NDIS_VLAN_INFO_INVALID 0xffffffff
#define HN_NDIS_RXCSUM_INFO_INVALID 0
#define HN_NDIS_HASH_INFO_INVALID 0
struct hn_rxinfo {
uint32_t vlan_info;
uint32_t csum_info;
uint32_t hash_info;
uint32_t hash_value;
};
#define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU)
#define HN_LRO_LENLIM_DEF (25 * ETHERMTU)
/* YYY 2*MTU is a bit rough, but should be good enough. */
@ -377,12 +398,18 @@ static void hn_link_status(struct hn_softc *);
static int hn_sendpkt_rndis_sglist(struct hn_tx_ring *, struct hn_txdesc *);
static int hn_sendpkt_rndis_chim(struct hn_tx_ring *, struct hn_txdesc *);
static int hn_set_rxfilter(struct hn_softc *);
static void hn_link_status_update(struct hn_softc *);
static void hn_network_change(struct hn_softc *);
static int hn_rndis_rxinfo(const void *, int, struct hn_rxinfo *);
static void hn_rndis_rx_data(struct hn_rx_ring *, const void *, int);
static void hn_rndis_rx_status(struct hn_softc *, const void *, int);
static void hn_nvs_handle_notify(struct hn_softc *sc,
const struct vmbus_chanpkt_hdr *pkt);
static void hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
const struct vmbus_chanpkt_hdr *pkt);
static void hn_nvs_handle_rxbuf(struct hn_softc *sc, struct hn_rx_ring *rxr,
static void hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr,
struct vmbus_channel *chan,
const struct vmbus_chanpkt_hdr *pkthdr);
static void hn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid);
@ -1006,7 +1033,7 @@ hn_netchg_status_taskfunc(void *xsc, int pending __unused)
hn_link_status(sc);
}
void
static void
hn_link_status_update(struct hn_softc *sc)
{
@ -1014,7 +1041,7 @@ hn_link_status_update(struct hn_softc *sc)
taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
}
void
static void
hn_network_change(struct hn_softc *sc)
{
@ -1615,15 +1642,9 @@ hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
}
#endif
/*
* Called when we receive a data packet from the "wire" on the
* specified device
*
* Note: This is no longer used as a callback
*/
int
static int
hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
const struct hn_recvinfo *info)
const struct hn_rxinfo *info)
{
struct ifnet *ifp = rxr->hn_ifp;
struct mbuf *m_new;
@ -4025,6 +4046,325 @@ hn_resume(struct hn_softc *sc)
hn_resume_mgmt(sc);
}
static void
hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_status_msg *msg;
int ofs;
if (dlen < sizeof(*msg)) {
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
return;
}
msg = data;
switch (msg->rm_status) {
case RNDIS_STATUS_MEDIA_CONNECT:
case RNDIS_STATUS_MEDIA_DISCONNECT:
hn_link_status_update(sc);
break;
case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
/* Not really useful; ignore. */
break;
case RNDIS_STATUS_NETWORK_CHANGE:
ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
if (dlen < ofs + msg->rm_stbuflen ||
msg->rm_stbuflen < sizeof(uint32_t)) {
if_printf(sc->hn_ifp, "network changed\n");
} else {
uint32_t change;
memcpy(&change, ((const uint8_t *)msg) + ofs,
sizeof(change));
if_printf(sc->hn_ifp, "network changed, change %u\n",
change);
}
hn_network_change(sc);
break;
default:
if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
msg->rm_status);
break;
}
}
static int
hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
{
const struct rndis_pktinfo *pi = info_data;
uint32_t mask = 0;
while (info_dlen != 0) {
const void *data;
uint32_t dlen;
if (__predict_false(info_dlen < sizeof(*pi)))
return (EINVAL);
if (__predict_false(info_dlen < pi->rm_size))
return (EINVAL);
info_dlen -= pi->rm_size;
if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
return (EINVAL);
if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
return (EINVAL);
dlen = pi->rm_size - pi->rm_pktinfooffset;
data = pi->rm_data;
switch (pi->rm_type) {
case NDIS_PKTINFO_TYPE_VLAN:
if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
return (EINVAL);
info->vlan_info = *((const uint32_t *)data);
mask |= HN_RXINFO_VLAN;
break;
case NDIS_PKTINFO_TYPE_CSUM:
if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
return (EINVAL);
info->csum_info = *((const uint32_t *)data);
mask |= HN_RXINFO_CSUM;
break;
case HN_NDIS_PKTINFO_TYPE_HASHVAL:
if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
return (EINVAL);
info->hash_value = *((const uint32_t *)data);
mask |= HN_RXINFO_HASHVAL;
break;
case HN_NDIS_PKTINFO_TYPE_HASHINF:
if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
return (EINVAL);
info->hash_info = *((const uint32_t *)data);
mask |= HN_RXINFO_HASHINF;
break;
default:
goto next;
}
if (mask == HN_RXINFO_ALL) {
/* All found; done */
break;
}
next:
pi = (const struct rndis_pktinfo *)
((const uint8_t *)pi + pi->rm_size);
}
/*
* Final fixup.
* - If there is no hash value, invalidate the hash info.
*/
if ((mask & HN_RXINFO_HASHVAL) == 0)
info->hash_info = HN_NDIS_HASH_INFO_INVALID;
return (0);
}
static __inline bool
hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
{
if (off < check_off) {
if (__predict_true(off + len <= check_off))
return (false);
} else if (off > check_off) {
if (__predict_true(check_off + check_len <= off))
return (false);
}
return (true);
}
static void
hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
{
const struct rndis_packet_msg *pkt;
struct hn_rxinfo info;
int data_off, pktinfo_off, data_len, pktinfo_len;
/*
* Check length.
*/
if (__predict_false(dlen < sizeof(*pkt))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
return;
}
pkt = data;
if (__predict_false(dlen < pkt->rm_len)) {
if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
"dlen %d, msglen %u\n", dlen, pkt->rm_len);
return;
}
if (__predict_false(pkt->rm_len <
pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
"msglen %u, data %u, oob %u, pktinfo %u\n",
pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
pkt->rm_pktinfolen);
return;
}
if (__predict_false(pkt->rm_datalen == 0)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
return;
}
/*
* Check offests.
*/
#define IS_OFFSET_INVALID(ofs) \
((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
/* XXX Hyper-V does not meet data offset alignment requirement */
if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"data offset %u\n", pkt->rm_dataoffset);
return;
}
if (__predict_false(pkt->rm_oobdataoffset > 0 &&
IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob offset %u\n", pkt->rm_oobdataoffset);
return;
}
if (__predict_true(pkt->rm_pktinfooffset > 0) &&
__predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo offset %u\n", pkt->rm_pktinfooffset);
return;
}
#undef IS_OFFSET_INVALID
data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
data_len = pkt->rm_datalen;
pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
pktinfo_len = pkt->rm_pktinfolen;
/*
* Check OOB coverage.
*/
if (__predict_false(pkt->rm_oobdatalen != 0)) {
int oob_off, oob_len;
if_printf(rxr->hn_ifp, "got oobdata\n");
oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
oob_len = pkt->rm_oobdatalen;
if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overflow, msglen %u, oob abs %d len %d\n",
pkt->rm_len, oob_off, oob_len);
return;
}
/*
* Check against data.
*/
if (hn_rndis_check_overlap(oob_off, oob_len,
data_off, data_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overlaps data, oob abs %d len %d, "
"data abs %d len %d\n",
oob_off, oob_len, data_off, data_len);
return;
}
/*
* Check against pktinfo.
*/
if (pktinfo_len != 0 &&
hn_rndis_check_overlap(oob_off, oob_len,
pktinfo_off, pktinfo_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overlaps pktinfo, oob abs %d len %d, "
"pktinfo abs %d len %d\n",
oob_off, oob_len, pktinfo_off, pktinfo_len);
return;
}
}
/*
* Check per-packet-info coverage and find useful per-packet-info.
*/
info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
info.hash_info = HN_NDIS_HASH_INFO_INVALID;
if (__predict_true(pktinfo_len != 0)) {
bool overlap;
int error;
if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo overflow, msglen %u, "
"pktinfo abs %d len %d\n",
pkt->rm_len, pktinfo_off, pktinfo_len);
return;
}
/*
* Check packet info coverage.
*/
overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
data_off, data_len);
if (__predict_false(overlap)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo overlap data, pktinfo abs %d len %d, "
"data abs %d len %d\n",
pktinfo_off, pktinfo_len, data_off, data_len);
return;
}
/*
* Find useful per-packet-info.
*/
error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
pktinfo_len, &info);
if (__predict_false(error)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
"pktinfo\n");
return;
}
}
if (__predict_false(data_off + data_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"data overflow, msglen %u, data abs %d len %d\n",
pkt->rm_len, data_off, data_len);
return;
}
hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
}
static __inline void
hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
{
const struct rndis_msghdr *hdr;
if (__predict_false(dlen < sizeof(*hdr))) {
if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
return;
}
hdr = data;
if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
/* Hot data path. */
hn_rndis_rx_data(rxr, data, dlen);
/* Done! */
return;
}
if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
else
hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
}
static void
hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
{
@ -4060,8 +4400,8 @@ hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
}
static void
hn_nvs_handle_rxbuf(struct hn_softc *sc, struct hn_rx_ring *rxr,
struct vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
const struct vmbus_chanpkt_hdr *pkthdr)
{
const struct vmbus_chanpkt_rxbuf *pkt;
const struct hn_nvs_hdr *nvs_hdr;
@ -4111,9 +4451,9 @@ hn_nvs_handle_rxbuf(struct hn_softc *sc, struct hn_rx_ring *rxr,
"ofs %d, len %d\n", i, ofs, len);
continue;
}
hv_rf_on_receive(sc, rxr, rxr->hn_rxbuf + ofs, len);
hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
}
/*
* Moved completion call back here so that all received
* messages (not just data messages) will trigger a response
@ -4177,7 +4517,7 @@ hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
hn_nvs_handle_comp(sc, chan, pkt);
break;
case VMBUS_CHANPKT_TYPE_RXBUF:
hn_nvs_handle_rxbuf(sc, rxr, chan, pkt);
hn_nvs_handle_rxbuf(rxr, chan, pkt);
break;
case VMBUS_CHANPKT_TYPE_INBAND:
hn_nvs_handle_notify(sc, pkt);

View File

@ -59,16 +59,6 @@ __FBSDID("$FreeBSD$");
#include <dev/hyperv/netvsc/hn_nvs.h>
#include <dev/hyperv/netvsc/hv_rndis_filter.h>
#define HV_RF_RECVINFO_VLAN 0x1
#define HV_RF_RECVINFO_CSUM 0x2
#define HV_RF_RECVINFO_HASHINF 0x4
#define HV_RF_RECVINFO_HASHVAL 0x8
#define HV_RF_RECVINFO_ALL \
(HV_RF_RECVINFO_VLAN | \
HV_RF_RECVINFO_CSUM | \
HV_RF_RECVINFO_HASHINF | \
HV_RF_RECVINFO_HASHVAL)
#define HN_RNDIS_RID_COMPAT_MASK 0xffff
#define HN_RNDIS_RID_COMPAT_MAX HN_RNDIS_RID_COMPAT_MASK
@ -89,11 +79,6 @@ __FBSDID("$FreeBSD$");
/*
* Forward declarations
*/
static void hv_rf_receive_indicate_status(struct hn_softc *sc,
const void *data, int dlen);
static void hv_rf_receive_data(struct hn_rx_ring *rxr,
const void *data, int dlen);
static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
const void *idata, size_t idlen, void *odata, size_t *odlen0);
static int hn_rndis_query2(struct hn_softc *sc, uint32_t oid,
@ -155,335 +140,22 @@ hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
return (pi->rm_data);
}
/*
* RNDIS filter receive indicate status
*/
static void
hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_status_msg *msg;
int ofs;
if (dlen < sizeof(*msg)) {
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
return;
}
msg = data;
switch (msg->rm_status) {
case RNDIS_STATUS_MEDIA_CONNECT:
case RNDIS_STATUS_MEDIA_DISCONNECT:
hn_link_status_update(sc);
break;
case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
/* Not really useful; ignore. */
break;
case RNDIS_STATUS_NETWORK_CHANGE:
ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
if (dlen < ofs + msg->rm_stbuflen ||
msg->rm_stbuflen < sizeof(uint32_t)) {
if_printf(sc->hn_ifp, "network changed\n");
} else {
uint32_t change;
memcpy(&change, ((const uint8_t *)msg) + ofs,
sizeof(change));
if_printf(sc->hn_ifp, "network changed, change %u\n",
change);
}
hn_network_change(sc);
break;
default:
/* TODO: */
if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
msg->rm_status);
break;
}
}
static int
hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
{
const struct rndis_pktinfo *pi = info_data;
uint32_t mask = 0;
while (info_dlen != 0) {
const void *data;
uint32_t dlen;
if (__predict_false(info_dlen < sizeof(*pi)))
return (EINVAL);
if (__predict_false(info_dlen < pi->rm_size))
return (EINVAL);
info_dlen -= pi->rm_size;
if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
return (EINVAL);
if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
return (EINVAL);
dlen = pi->rm_size - pi->rm_pktinfooffset;
data = pi->rm_data;
switch (pi->rm_type) {
case NDIS_PKTINFO_TYPE_VLAN:
if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
return (EINVAL);
info->vlan_info = *((const uint32_t *)data);
mask |= HV_RF_RECVINFO_VLAN;
break;
case NDIS_PKTINFO_TYPE_CSUM:
if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
return (EINVAL);
info->csum_info = *((const uint32_t *)data);
mask |= HV_RF_RECVINFO_CSUM;
break;
case HN_NDIS_PKTINFO_TYPE_HASHVAL:
if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
return (EINVAL);
info->hash_value = *((const uint32_t *)data);
mask |= HV_RF_RECVINFO_HASHVAL;
break;
case HN_NDIS_PKTINFO_TYPE_HASHINF:
if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
return (EINVAL);
info->hash_info = *((const uint32_t *)data);
mask |= HV_RF_RECVINFO_HASHINF;
break;
default:
goto next;
}
if (mask == HV_RF_RECVINFO_ALL) {
/* All found; done */
break;
}
next:
pi = (const struct rndis_pktinfo *)
((const uint8_t *)pi + pi->rm_size);
}
/*
* Final fixup.
* - If there is no hash value, invalidate the hash info.
*/
if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
info->hash_info = HN_NDIS_HASH_INFO_INVALID;
return (0);
}
static __inline bool
hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
{
if (off < check_off) {
if (__predict_true(off + len <= check_off))
return (false);
} else if (off > check_off) {
if (__predict_true(check_off + check_len <= off))
return (false);
}
return (true);
}
/*
* RNDIS filter receive data
*/
static void
hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
{
const struct rndis_packet_msg *pkt;
struct hn_recvinfo info;
int data_off, pktinfo_off, data_len, pktinfo_len;
/*
* Check length.
*/
if (__predict_false(dlen < sizeof(*pkt))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
return;
}
pkt = data;
if (__predict_false(dlen < pkt->rm_len)) {
if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
"dlen %d, msglen %u\n", dlen, pkt->rm_len);
return;
}
if (__predict_false(pkt->rm_len <
pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
"msglen %u, data %u, oob %u, pktinfo %u\n",
pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
pkt->rm_pktinfolen);
return;
}
if (__predict_false(pkt->rm_datalen == 0)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
return;
}
/*
* Check offests.
*/
#define IS_OFFSET_INVALID(ofs) \
((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
/* XXX Hyper-V does not meet data offset alignment requirement */
if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"data offset %u\n", pkt->rm_dataoffset);
return;
}
if (__predict_false(pkt->rm_oobdataoffset > 0 &&
IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob offset %u\n", pkt->rm_oobdataoffset);
return;
}
if (__predict_true(pkt->rm_pktinfooffset > 0) &&
__predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo offset %u\n", pkt->rm_pktinfooffset);
return;
}
#undef IS_OFFSET_INVALID
data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
data_len = pkt->rm_datalen;
pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
pktinfo_len = pkt->rm_pktinfolen;
/*
* Check OOB coverage.
*/
if (__predict_false(pkt->rm_oobdatalen != 0)) {
int oob_off, oob_len;
if_printf(rxr->hn_ifp, "got oobdata\n");
oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
oob_len = pkt->rm_oobdatalen;
if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overflow, msglen %u, oob abs %d len %d\n",
pkt->rm_len, oob_off, oob_len);
return;
}
/*
* Check against data.
*/
if (hn_rndis_check_overlap(oob_off, oob_len,
data_off, data_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overlaps data, oob abs %d len %d, "
"data abs %d len %d\n",
oob_off, oob_len, data_off, data_len);
return;
}
/*
* Check against pktinfo.
*/
if (pktinfo_len != 0 &&
hn_rndis_check_overlap(oob_off, oob_len,
pktinfo_off, pktinfo_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"oob overlaps pktinfo, oob abs %d len %d, "
"pktinfo abs %d len %d\n",
oob_off, oob_len, pktinfo_off, pktinfo_len);
return;
}
}
/*
* Check per-packet-info coverage and find useful per-packet-info.
*/
info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
info.hash_info = HN_NDIS_HASH_INFO_INVALID;
if (__predict_true(pktinfo_len != 0)) {
bool overlap;
int error;
if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo overflow, msglen %u, "
"pktinfo abs %d len %d\n",
pkt->rm_len, pktinfo_off, pktinfo_len);
return;
}
/*
* Check packet info coverage.
*/
overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
data_off, data_len);
if (__predict_false(overlap)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"pktinfo overlap data, pktinfo abs %d len %d, "
"data abs %d len %d\n",
pktinfo_off, pktinfo_len, data_off, data_len);
return;
}
/*
* Find useful per-packet-info.
*/
error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
pktinfo_len, &info);
if (__predict_false(error)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
"pktinfo\n");
return;
}
}
if (__predict_false(data_off + data_len > pkt->rm_len)) {
if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
"data overflow, msglen %u, data abs %d len %d\n",
pkt->rm_len, data_off, data_len);
return;
}
hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
}
/*
* RNDIS filter on receive
*/
void
hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
const void *data, int dlen)
hn_rndis_rx_ctrl(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_comp_hdr *comp;
const struct rndis_msghdr *hdr;
if (__predict_false(dlen < sizeof(*hdr))) {
if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
return;
}
KASSERT(dlen >= sizeof(*hdr), ("invalid RNDIS msg\n"));
hdr = data;
switch (hdr->rm_type) {
case REMOTE_NDIS_PACKET_MSG:
hv_rf_receive_data(rxr, data, dlen);
break;
case REMOTE_NDIS_INITIALIZE_CMPLT:
case REMOTE_NDIS_QUERY_CMPLT:
case REMOTE_NDIS_SET_CMPLT:
case REMOTE_NDIS_KEEPALIVE_CMPLT: /* unused */
if (dlen < sizeof(*comp)) {
if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
if_printf(sc->hn_ifp, "invalid RNDIS cmplt\n");
return;
}
comp = data;
@ -493,10 +165,6 @@ hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
break;
case REMOTE_NDIS_INDICATE_STATUS_MSG:
hv_rf_receive_indicate_status(sc, data, dlen);
break;
case REMOTE_NDIS_RESET_CMPLT:
/*
* Reset completed, no rid.
@ -505,11 +173,11 @@ hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
* RESET is not issued by hn(4), so this message should
* _not_ be observed.
*/
if_printf(rxr->hn_ifp, "RESET cmplt received\n");
if_printf(sc->hn_ifp, "RESET cmplt received\n");
break;
default:
if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
if_printf(sc->hn_ifp, "unknown RNDIS msg 0x%x\n",
hdr->rm_type);
break;
}

View File

@ -31,16 +31,9 @@
#ifndef __HV_RNDIS_FILTER_H__
#define __HV_RNDIS_FILTER_H__
#include <sys/param.h>
#include <net/ethernet.h>
#include <dev/hyperv/netvsc/if_hnvar.h>
struct hn_softc;
/*
* Externs
*/
struct hn_rx_ring;
void hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
const void *data, int dlen);
void hn_rndis_rx_ctrl(struct hn_softc *sc, const void *data,
int dlen);
#endif /* __HV_RNDIS_FILTER_H__ */

View File

@ -51,17 +51,6 @@
#define HN_GPACNT_MAX 32
#define HN_NDIS_VLAN_INFO_INVALID 0xffffffff
#define HN_NDIS_RXCSUM_INFO_INVALID 0
#define HN_NDIS_HASH_INFO_INVALID 0
struct hn_recvinfo {
uint32_t vlan_info;
uint32_t csum_info;
uint32_t hash_info;
uint32_t hash_value;
};
struct hn_txdesc;
#ifndef HN_USE_TXDESC_BUFRING
SLIST_HEAD(hn_txdesc_list, hn_txdesc);
@ -256,9 +245,4 @@ int hn_rndis_get_linkstatus(struct hn_softc *sc,
/* filter: NDIS_PACKET_TYPE_. */
int hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter);
int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
const struct hn_recvinfo *info);
void hn_link_status_update(struct hn_softc *sc);
void hn_network_change(struct hn_softc *sc);
#endif /* !_IF_HNVAR_H_ */