hyperv/hn: Use vmbus xact for RNDIS query.
And switch MAC address query to use new RNDIS query function. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7639
This commit is contained in:
parent
22983a8768
commit
cc3d96db55
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=304832
@ -96,6 +96,8 @@ static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
|
||||
static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
|
||||
struct hn_softc *sc, struct vmbus_channel *chan,
|
||||
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 __inline uint32_t
|
||||
hn_rndis_rid(struct hn_softc *sc)
|
||||
@ -695,13 +697,23 @@ hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
|
||||
/*
|
||||
* RNDIS filter query device MAC address
|
||||
*/
|
||||
static inline int
|
||||
static int
|
||||
hv_rf_query_device_mac(rndis_device *device)
|
||||
{
|
||||
uint32_t size = ETHER_ADDR_LEN;
|
||||
struct hn_softc *sc = device->sc;
|
||||
size_t hwaddr_len;
|
||||
int error;
|
||||
|
||||
return (hv_rf_query_device(device,
|
||||
RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
|
||||
hwaddr_len = ETHER_ADDR_LEN;
|
||||
error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
|
||||
device->hw_mac_addr, &hwaddr_len);
|
||||
if (error)
|
||||
return error;
|
||||
if (hwaddr_len != ETHER_ADDR_LEN) {
|
||||
if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -892,12 +904,12 @@ hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
|
||||
|
||||
static const void *
|
||||
hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
|
||||
size_t reqlen, size_t min_complen, uint32_t comp_type)
|
||||
size_t reqlen, size_t *comp_len0, uint32_t comp_type)
|
||||
{
|
||||
struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
|
||||
const struct rndis_comp_hdr *comp;
|
||||
bus_addr_t paddr;
|
||||
size_t comp_len;
|
||||
size_t comp_len, min_complen = *comp_len0;
|
||||
int gpa_cnt, error;
|
||||
|
||||
KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
|
||||
@ -946,7 +958,14 @@ hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid
|
||||
* Check this RNDIS complete message.
|
||||
*/
|
||||
if (comp_len < min_complen) {
|
||||
if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n", comp_len);
|
||||
if (comp_len >= sizeof(*comp)) {
|
||||
/* rm_status field is valid */
|
||||
if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
|
||||
"status 0x%08x\n", comp_len, comp->rm_status);
|
||||
} else {
|
||||
if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
|
||||
comp_len);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
if (comp->rm_len < min_complen) {
|
||||
@ -965,9 +984,100 @@ hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid
|
||||
return (NULL);
|
||||
}
|
||||
/* All pass! */
|
||||
*comp_len0 = comp_len;
|
||||
return (comp);
|
||||
}
|
||||
|
||||
static int
|
||||
hn_rndis_query(struct hn_softc *sc, uint32_t oid,
|
||||
const void *idata, size_t idlen, void *odata, size_t *odlen0)
|
||||
{
|
||||
struct rndis_query_req *req;
|
||||
const struct rndis_query_comp *comp;
|
||||
struct vmbus_xact *xact;
|
||||
size_t reqlen, odlen = *odlen0, comp_len;
|
||||
int error, ofs;
|
||||
uint32_t rid;
|
||||
|
||||
reqlen = sizeof(*req) + idlen;
|
||||
xact = vmbus_xact_get(sc->hn_xact, reqlen);
|
||||
if (xact == NULL) {
|
||||
if_printf(sc->hn_ifp, "no xact for RNDIS query\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
rid = hn_rndis_rid(sc);
|
||||
req = vmbus_xact_req_data(xact);
|
||||
req->rm_type = REMOTE_NDIS_QUERY_MSG;
|
||||
req->rm_len = reqlen;
|
||||
req->rm_rid = rid;
|
||||
req->rm_oid = oid;
|
||||
/*
|
||||
* XXX
|
||||
* This is _not_ RNDIS Spec conforming:
|
||||
* "This MUST be set to 0 when there is no input data
|
||||
* associated with the OID."
|
||||
*
|
||||
* If this field was set to 0 according to the RNDIS Spec,
|
||||
* Hyper-V would set non-SUCCESS status in the query
|
||||
* completion.
|
||||
*/
|
||||
req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
|
||||
|
||||
if (idlen > 0) {
|
||||
req->rm_infobuflen = idlen;
|
||||
/* Input data immediately follows RNDIS query. */
|
||||
memcpy(req + 1, idata, idlen);
|
||||
}
|
||||
|
||||
comp_len = sizeof(*comp) + odlen;
|
||||
comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
|
||||
REMOTE_NDIS_QUERY_CMPLT);
|
||||
if (comp == NULL) {
|
||||
if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
|
||||
error = EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
|
||||
if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
|
||||
"status 0x%08x\n", oid, comp->rm_status);
|
||||
error = EIO;
|
||||
goto done;
|
||||
}
|
||||
if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
|
||||
/* No output data! */
|
||||
if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
|
||||
*odlen0 = 0;
|
||||
error = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check output data length and offset.
|
||||
*/
|
||||
/* ofs is the offset from the beginning of comp. */
|
||||
ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
|
||||
if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
|
||||
if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
|
||||
"%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save output data.
|
||||
*/
|
||||
if (comp->rm_infobuflen < odlen)
|
||||
odlen = comp->rm_infobuflen;
|
||||
memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
|
||||
*odlen0 = odlen;
|
||||
|
||||
error = 0;
|
||||
done:
|
||||
vmbus_xact_put(xact);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* RNDIS filter init device
|
||||
*/
|
||||
@ -978,6 +1088,7 @@ hv_rf_init_device(rndis_device *device)
|
||||
struct rndis_init_req *req;
|
||||
const struct rndis_init_comp *comp;
|
||||
struct vmbus_xact *xact;
|
||||
size_t comp_len;
|
||||
uint32_t rid;
|
||||
int error;
|
||||
|
||||
@ -998,8 +1109,9 @@ hv_rf_init_device(rndis_device *device)
|
||||
req->rm_ver_minor = RNDIS_VERSION_MINOR;
|
||||
req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
|
||||
|
||||
comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req),
|
||||
RNDIS_INIT_COMP_SIZE_MIN, REMOTE_NDIS_INITIALIZE_CMPLT);
|
||||
comp_len = RNDIS_INIT_COMP_SIZE_MIN;
|
||||
comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
|
||||
REMOTE_NDIS_INITIALIZE_CMPLT);
|
||||
if (comp == NULL) {
|
||||
if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
|
||||
error = EIO;
|
||||
|
@ -172,6 +172,10 @@ struct rndis_query_req {
|
||||
uint32_t rm_devicevchdl;
|
||||
};
|
||||
|
||||
#define RNDIS_QUERY_REQ_INFOBUFOFFSET \
|
||||
(sizeof(struct rndis_query_req) - \
|
||||
__offsetof(struct rndis_query_req, rm_rid))
|
||||
|
||||
struct rndis_query_comp {
|
||||
uint32_t rm_type;
|
||||
uint32_t rm_len;
|
||||
@ -181,6 +185,9 @@ struct rndis_query_comp {
|
||||
uint32_t rm_infobufoffset;
|
||||
};
|
||||
|
||||
#define RNDIS_QUERY_COMP_INFOBUFABS(ofs) \
|
||||
((ofs) + __offsetof(struct rndis_query_req, rm_rid))
|
||||
|
||||
/* Send a set object request. */
|
||||
#define REMOTE_NDIS_SET_MSG 0x00000005
|
||||
#define REMOTE_NDIS_SET_CMPLT 0x80000005
|
||||
|
Loading…
Reference in New Issue
Block a user