|
@@ -59,6 +59,14 @@
|
|
|
#define OPA_LINK_WIDTH_RESET_OLD 0x0fff
|
|
|
#define OPA_LINK_WIDTH_RESET 0xffff
|
|
|
|
|
|
+static int smp_length_check(u32 data_size, u32 request_len)
|
|
|
+{
|
|
|
+ if (unlikely(request_len < data_size))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int reply(struct ib_mad_hdr *smp)
|
|
|
{
|
|
|
/*
|
|
@@ -105,7 +113,7 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
|
|
|
return;
|
|
|
|
|
|
/* o14-3.2.1 */
|
|
|
- if (ppd_from_ibp(ibp)->lstate != IB_PORT_ACTIVE)
|
|
|
+ if (driver_lstate(ppd_from_ibp(ibp)) != IB_PORT_ACTIVE)
|
|
|
return;
|
|
|
|
|
|
/* o14-2 */
|
|
@@ -172,10 +180,10 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Send a bad [PQ]_Key trap (ch. 14.3.8).
|
|
|
+ * Send a bad P_Key trap (ch. 14.3.8).
|
|
|
*/
|
|
|
-void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
|
|
|
- u32 qp1, u32 qp2, u16 lid1, u16 lid2)
|
|
|
+void hfi1_bad_pkey(struct hfi1_ibport *ibp, u32 key, u32 sl,
|
|
|
+ u32 qp1, u32 qp2, u16 lid1, u16 lid2)
|
|
|
{
|
|
|
struct opa_mad_notice_attr data;
|
|
|
u32 lid = ppd_from_ibp(ibp)->lid;
|
|
@@ -183,17 +191,13 @@ void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
|
|
|
u32 _lid2 = lid2;
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
-
|
|
|
- if (trap_num == OPA_TRAP_BAD_P_KEY)
|
|
|
- ibp->rvp.pkey_violations++;
|
|
|
- else
|
|
|
- ibp->rvp.qkey_violations++;
|
|
|
ibp->rvp.n_pkt_drops++;
|
|
|
+ ibp->rvp.pkey_violations++;
|
|
|
|
|
|
/* Send violation trap */
|
|
|
data.generic_type = IB_NOTICE_TYPE_SECURITY;
|
|
|
data.prod_type_lsb = IB_NOTICE_PROD_CA;
|
|
|
- data.trap_num = trap_num;
|
|
|
+ data.trap_num = OPA_TRAP_BAD_P_KEY;
|
|
|
data.issuer_lid = cpu_to_be32(lid);
|
|
|
data.ntc_257_258.lid1 = cpu_to_be32(_lid1);
|
|
|
data.ntc_257_258.lid2 = cpu_to_be32(_lid2);
|
|
@@ -260,6 +264,7 @@ void hfi1_cap_mask_chg(struct rvt_dev_info *rdi, u8 port_num)
|
|
|
data.issuer_lid = cpu_to_be32(lid);
|
|
|
data.ntc_144.lid = data.issuer_lid;
|
|
|
data.ntc_144.new_cap_mask = cpu_to_be32(ibp->rvp.port_cap_flags);
|
|
|
+ data.ntc_144.cap_mask3 = cpu_to_be16(ibp->rvp.port_cap3_flags);
|
|
|
|
|
|
send_trap(ibp, &data, sizeof(data));
|
|
|
}
|
|
@@ -307,11 +312,11 @@ void hfi1_node_desc_chg(struct hfi1_ibport *ibp)
|
|
|
|
|
|
static int __subn_get_opa_nodedesc(struct opa_smp *smp, u32 am,
|
|
|
u8 *data, struct ib_device *ibdev,
|
|
|
- u8 port, u32 *resp_len)
|
|
|
+ u8 port, u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct opa_node_description *nd;
|
|
|
|
|
|
- if (am) {
|
|
|
+ if (am || smp_length_check(sizeof(*nd), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -328,7 +333,7 @@ static int __subn_get_opa_nodedesc(struct opa_smp *smp, u32 am,
|
|
|
|
|
|
static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct opa_node_info *ni;
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
@@ -338,6 +343,7 @@ static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
/* GUID 0 is illegal */
|
|
|
if (am || pidx >= dd->num_pports || ibdev->node_guid == 0 ||
|
|
|
+ smp_length_check(sizeof(*ni), max_len) ||
|
|
|
get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
@@ -519,7 +525,7 @@ void read_ltp_rtt(struct hfi1_devdata *dd)
|
|
|
|
|
|
static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
int i;
|
|
|
struct hfi1_devdata *dd;
|
|
@@ -535,7 +541,7 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
u32 buffer_units;
|
|
|
u64 tmp = 0;
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 || smp_length_check(sizeof(*pi), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -605,7 +611,7 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
ppd->offline_disabled_reason;
|
|
|
|
|
|
pi->port_states.portphysstate_portstate =
|
|
|
- (hfi1_ibphys_portstate(ppd) << 4) | state;
|
|
|
+ (driver_pstate(ppd) << 4) | state;
|
|
|
|
|
|
pi->mkeyprotect_lmc = (ibp->rvp.mkeyprot << 6) | ppd->lmc;
|
|
|
|
|
@@ -704,11 +710,7 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
buffer_units |= (dd->vl15_init << 11) & OPA_PI_MASK_BUF_UNIT_VL15_INIT;
|
|
|
pi->buffer_units = cpu_to_be32(buffer_units);
|
|
|
|
|
|
- pi->opa_cap_mask = cpu_to_be16(OPA_CAP_MASK3_IsSharedSpaceSupported |
|
|
|
- OPA_CAP_MASK3_IsEthOnFabricSupported);
|
|
|
- /* Driver does not support mcast/collective configuration */
|
|
|
- pi->opa_cap_mask &=
|
|
|
- cpu_to_be16(~OPA_CAP_MASK3_IsAddrRangeConfigSupported);
|
|
|
+ pi->opa_cap_mask = cpu_to_be16(ibp->rvp.port_cap3_flags);
|
|
|
pi->collectivemask_multicastmask = ((HFI1_COLLECTIVE_NR & 0x7)
|
|
|
<< 3 | (HFI1_MCAST_NR & 0x7));
|
|
|
|
|
@@ -748,7 +750,7 @@ static int get_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys)
|
|
|
|
|
|
static int __subn_get_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
u32 n_blocks_req = OPA_AM_NBLK(am);
|
|
@@ -771,6 +773,11 @@ static int __subn_get_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
size = (n_blocks_req * OPA_PARTITION_TABLE_BLK_SIZE) * sizeof(u16);
|
|
|
|
|
|
+ if (smp_length_check(size, max_len)) {
|
|
|
+ smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ return reply((struct ib_mad_hdr *)smp);
|
|
|
+ }
|
|
|
+
|
|
|
if (start_block + n_blocks_req > n_blocks_avail ||
|
|
|
n_blocks_req > OPA_NUM_PKEY_BLOCKS_PER_SMP) {
|
|
|
pr_warn("OPA Get PKey AM Invalid : s 0x%x; req 0x%x; "
|
|
@@ -1074,7 +1081,7 @@ static int set_port_states(struct hfi1_pportdata *ppd, struct opa_smp *smp,
|
|
|
*/
|
|
|
static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct opa_port_info *pi = (struct opa_port_info *)data;
|
|
|
struct ib_event event;
|
|
@@ -1095,7 +1102,8 @@ static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
int ret, i, invalid = 0, call_set_mtu = 0;
|
|
|
int call_link_downgrade_policy = 0;
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 ||
|
|
|
+ smp_length_check(sizeof(*pi), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1346,7 +1354,8 @@ static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len);
|
|
|
+ ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
|
|
|
/* restore re-reg bit per o14-12.2.1 */
|
|
|
pi->clientrereg_subnettimeout |= clientrereg;
|
|
@@ -1363,7 +1372,8 @@ static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
return ret;
|
|
|
|
|
|
get_only:
|
|
|
- return __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1424,7 +1434,7 @@ static int set_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys)
|
|
|
|
|
|
static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
u32 n_blocks_sent = OPA_AM_NBLK(am);
|
|
@@ -1434,6 +1444,7 @@ static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
int i;
|
|
|
u16 n_blocks_avail;
|
|
|
unsigned npkeys = hfi1_get_npkeys(dd);
|
|
|
+ u32 size = 0;
|
|
|
|
|
|
if (n_blocks_sent == 0) {
|
|
|
pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n",
|
|
@@ -1444,6 +1455,13 @@ static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
n_blocks_avail = (u16)(npkeys / OPA_PARTITION_TABLE_BLK_SIZE) + 1;
|
|
|
|
|
|
+ size = sizeof(u16) * (n_blocks_sent * OPA_PARTITION_TABLE_BLK_SIZE);
|
|
|
+
|
|
|
+ if (smp_length_check(size, max_len)) {
|
|
|
+ smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ return reply((struct ib_mad_hdr *)smp);
|
|
|
+ }
|
|
|
+
|
|
|
if (start_block + n_blocks_sent > n_blocks_avail ||
|
|
|
n_blocks_sent > OPA_NUM_PKEY_BLOCKS_PER_SMP) {
|
|
|
pr_warn("OPA Set PKey AM Invalid : s 0x%x; req 0x%x; avail 0x%x; blk/smp 0x%lx\n",
|
|
@@ -1461,7 +1479,8 @@ static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
- return __subn_get_opa_pkeytable(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_pkeytable(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
#define ILLEGAL_VL 12
|
|
@@ -1522,14 +1541,14 @@ static int get_sc2vlt_tables(struct hfi1_devdata *dd, void *data)
|
|
|
|
|
|
static int __subn_get_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
u8 *p = data;
|
|
|
size_t size = ARRAY_SIZE(ibp->sl_to_sc); /* == 32 */
|
|
|
unsigned i;
|
|
|
|
|
|
- if (am) {
|
|
|
+ if (am || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1545,14 +1564,15 @@ static int __subn_get_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
u8 *p = data;
|
|
|
+ size_t size = ARRAY_SIZE(ibp->sl_to_sc);
|
|
|
int i;
|
|
|
u8 sc;
|
|
|
|
|
|
- if (am) {
|
|
|
+ if (am || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1567,19 +1587,20 @@ static int __subn_set_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
u8 *p = data;
|
|
|
size_t size = ARRAY_SIZE(ibp->sc_to_sl); /* == 32 */
|
|
|
unsigned i;
|
|
|
|
|
|
- if (am) {
|
|
|
+ if (am || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1595,13 +1616,14 @@ static int __subn_get_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
+ size_t size = ARRAY_SIZE(ibp->sc_to_sl);
|
|
|
u8 *p = data;
|
|
|
int i;
|
|
|
|
|
|
- if (am) {
|
|
|
+ if (am || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1609,19 +1631,20 @@ static int __subn_set_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++)
|
|
|
ibp->sc_to_sl[i] = *p++;
|
|
|
|
|
|
- return __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 n_blocks = OPA_AM_NBLK(am);
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
void *vp = (void *)data;
|
|
|
size_t size = 4 * sizeof(u64);
|
|
|
|
|
|
- if (n_blocks != 1) {
|
|
|
+ if (n_blocks != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1636,7 +1659,7 @@ static int __subn_get_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 n_blocks = OPA_AM_NBLK(am);
|
|
|
int async_update = OPA_AM_ASYNC(am);
|
|
@@ -1644,8 +1667,15 @@ static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
void *vp = (void *)data;
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
int lstate;
|
|
|
+ /*
|
|
|
+ * set_sc2vlt_tables writes the information contained in *data
|
|
|
+ * to four 64-bit registers SendSC2VLt[0-3]. We need to make
|
|
|
+ * sure *max_len is not greater than the total size of the four
|
|
|
+ * SendSC2VLt[0-3] registers.
|
|
|
+ */
|
|
|
+ size_t size = 4 * sizeof(u64);
|
|
|
|
|
|
- if (n_blocks != 1 || async_update) {
|
|
|
+ if (n_blocks != 1 || async_update || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1665,27 +1695,28 @@ static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
set_sc2vlt_tables(dd, vp);
|
|
|
|
|
|
- return __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 n_blocks = OPA_AM_NPORT(am);
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
void *vp = (void *)data;
|
|
|
- int size;
|
|
|
+ int size = sizeof(struct sc2vlnt);
|
|
|
|
|
|
- if (n_blocks != 1) {
|
|
|
+ if (n_blocks != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
ppd = dd->pport + (port - 1);
|
|
|
|
|
|
- size = fm_get_table(ppd, FM_TBL_SC2VLNT, vp);
|
|
|
+ fm_get_table(ppd, FM_TBL_SC2VLNT, vp);
|
|
|
|
|
|
if (resp_len)
|
|
|
*resp_len += size;
|
|
@@ -1695,15 +1726,16 @@ static int __subn_get_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 n_blocks = OPA_AM_NPORT(am);
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
void *vp = (void *)data;
|
|
|
int lstate;
|
|
|
+ int size = sizeof(struct sc2vlnt);
|
|
|
|
|
|
- if (n_blocks != 1) {
|
|
|
+ if (n_blocks != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1721,12 +1753,12 @@ static int __subn_set_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
fm_set_table(ppd, FM_TBL_SC2VLNT, vp);
|
|
|
|
|
|
return __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 nports = OPA_AM_NPORT(am);
|
|
|
u32 start_of_sm_config = OPA_AM_START_SM_CFG(am);
|
|
@@ -1735,7 +1767,7 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
struct opa_port_state_info *psi = (struct opa_port_state_info *)data;
|
|
|
|
|
|
- if (nports != 1) {
|
|
|
+ if (nports != 1 || smp_length_check(sizeof(*psi), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1755,7 +1787,7 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
ppd->offline_disabled_reason;
|
|
|
|
|
|
psi->port_states.portphysstate_portstate =
|
|
|
- (hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf);
|
|
|
+ (driver_pstate(ppd) << 4) | (lstate & 0xf);
|
|
|
psi->link_width_downgrade_tx_active =
|
|
|
cpu_to_be16(ppd->link_width_downgrade_tx_active);
|
|
|
psi->link_width_downgrade_rx_active =
|
|
@@ -1768,7 +1800,7 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
u32 nports = OPA_AM_NPORT(am);
|
|
|
u32 start_of_sm_config = OPA_AM_START_SM_CFG(am);
|
|
@@ -1779,7 +1811,7 @@ static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct opa_port_state_info *psi = (struct opa_port_state_info *)data;
|
|
|
int ret, invalid = 0;
|
|
|
|
|
|
- if (nports != 1) {
|
|
|
+ if (nports != 1 || smp_length_check(sizeof(*psi), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1809,19 +1841,21 @@ static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
if (invalid)
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
|
|
|
- return __subn_get_opa_psi(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_psi(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_cable_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
u32 addr = OPA_AM_CI_ADDR(am);
|
|
|
u32 len = OPA_AM_CI_LEN(am) + 1;
|
|
|
int ret;
|
|
|
|
|
|
- if (dd->pport->port_type != PORT_TYPE_QSFP) {
|
|
|
+ if (dd->pport->port_type != PORT_TYPE_QSFP ||
|
|
|
+ smp_length_check(len, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1864,21 +1898,22 @@ static int __subn_get_opa_cable_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_bct(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
- struct ib_device *ibdev, u8 port, u32 *resp_len)
|
|
|
+ struct ib_device *ibdev, u8 port, u32 *resp_len,
|
|
|
+ u32 max_len)
|
|
|
{
|
|
|
u32 num_ports = OPA_AM_NPORT(am);
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
struct buffer_control *p = (struct buffer_control *)data;
|
|
|
- int size;
|
|
|
+ int size = sizeof(struct buffer_control);
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
ppd = dd->pport + (port - 1);
|
|
|
- size = fm_get_table(ppd, FM_TBL_BUFFER_CONTROL, p);
|
|
|
+ fm_get_table(ppd, FM_TBL_BUFFER_CONTROL, p);
|
|
|
trace_bct_get(dd, p);
|
|
|
if (resp_len)
|
|
|
*resp_len += size;
|
|
@@ -1887,14 +1922,15 @@ static int __subn_get_opa_bct(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
}
|
|
|
|
|
|
static int __subn_set_opa_bct(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
- struct ib_device *ibdev, u8 port, u32 *resp_len)
|
|
|
+ struct ib_device *ibdev, u8 port, u32 *resp_len,
|
|
|
+ u32 max_len)
|
|
|
{
|
|
|
u32 num_ports = OPA_AM_NPORT(am);
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct hfi1_pportdata *ppd;
|
|
|
struct buffer_control *p = (struct buffer_control *)data;
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 || smp_length_check(sizeof(*p), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1905,41 +1941,43 @@ static int __subn_set_opa_bct(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
- return __subn_get_opa_bct(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_bct(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port));
|
|
|
u32 num_ports = OPA_AM_NPORT(am);
|
|
|
u8 section = (am & 0x00ff0000) >> 16;
|
|
|
u8 *p = data;
|
|
|
- int size = 0;
|
|
|
+ int size = 256;
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
switch (section) {
|
|
|
case OPA_VLARB_LOW_ELEMENTS:
|
|
|
- size = fm_get_table(ppd, FM_TBL_VL_LOW_ARB, p);
|
|
|
+ fm_get_table(ppd, FM_TBL_VL_LOW_ARB, p);
|
|
|
break;
|
|
|
case OPA_VLARB_HIGH_ELEMENTS:
|
|
|
- size = fm_get_table(ppd, FM_TBL_VL_HIGH_ARB, p);
|
|
|
+ fm_get_table(ppd, FM_TBL_VL_HIGH_ARB, p);
|
|
|
break;
|
|
|
case OPA_VLARB_PREEMPT_ELEMENTS:
|
|
|
- size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_ELEMS, p);
|
|
|
+ fm_get_table(ppd, FM_TBL_VL_PREEMPT_ELEMS, p);
|
|
|
break;
|
|
|
case OPA_VLARB_PREEMPT_MATRIX:
|
|
|
- size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_MATRIX, p);
|
|
|
+ fm_get_table(ppd, FM_TBL_VL_PREEMPT_MATRIX, p);
|
|
|
break;
|
|
|
default:
|
|
|
pr_warn("OPA SubnGet(VL Arb) AM Invalid : 0x%x\n",
|
|
|
be32_to_cpu(smp->attr_mod));
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ size = 0;
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -1951,14 +1989,15 @@ static int __subn_get_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port));
|
|
|
u32 num_ports = OPA_AM_NPORT(am);
|
|
|
u8 section = (am & 0x00ff0000) >> 16;
|
|
|
u8 *p = data;
|
|
|
+ int size = 256;
|
|
|
|
|
|
- if (num_ports != 1) {
|
|
|
+ if (num_ports != 1 || smp_length_check(size, max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -1986,7 +2025,8 @@ static int __subn_set_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- return __subn_get_opa_vl_arb(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_vl_arb(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
struct opa_pma_mad {
|
|
@@ -3282,13 +3322,18 @@ struct opa_congestion_info_attr {
|
|
|
|
|
|
static int __subn_get_opa_cong_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct opa_congestion_info_attr *p =
|
|
|
(struct opa_congestion_info_attr *)data;
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
|
|
|
|
|
|
+ if (smp_length_check(sizeof(*p), max_len)) {
|
|
|
+ smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ return reply((struct ib_mad_hdr *)smp);
|
|
|
+ }
|
|
|
+
|
|
|
p->congestion_info = 0;
|
|
|
p->control_table_cap = ppd->cc_max_table_entries;
|
|
|
p->congestion_log_length = OPA_CONG_LOG_ELEMS;
|
|
@@ -3301,7 +3346,7 @@ static int __subn_get_opa_cong_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am,
|
|
|
u8 *data, struct ib_device *ibdev,
|
|
|
- u8 port, u32 *resp_len)
|
|
|
+ u8 port, u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
int i;
|
|
|
struct opa_congestion_setting_attr *p =
|
|
@@ -3311,6 +3356,11 @@ static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am,
|
|
|
struct opa_congestion_setting_entry_shadow *entries;
|
|
|
struct cc_state *cc_state;
|
|
|
|
|
|
+ if (smp_length_check(sizeof(*p), max_len)) {
|
|
|
+ smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ return reply((struct ib_mad_hdr *)smp);
|
|
|
+ }
|
|
|
+
|
|
|
rcu_read_lock();
|
|
|
|
|
|
cc_state = get_cc_state(ppd);
|
|
@@ -3385,7 +3435,7 @@ static void apply_cc_state(struct hfi1_pportdata *ppd)
|
|
|
|
|
|
static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct opa_congestion_setting_attr *p =
|
|
|
(struct opa_congestion_setting_attr *)data;
|
|
@@ -3394,6 +3444,11 @@ static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct opa_congestion_setting_entry_shadow *entries;
|
|
|
int i;
|
|
|
|
|
|
+ if (smp_length_check(sizeof(*p), max_len)) {
|
|
|
+ smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
+ return reply((struct ib_mad_hdr *)smp);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Save details from packet into the ppd. Hold the cc_state_lock so
|
|
|
* our information is consistent with anyone trying to apply the state.
|
|
@@ -3415,12 +3470,12 @@ static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
apply_cc_state(ppd);
|
|
|
|
|
|
return __subn_get_opa_cong_setting(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
}
|
|
|
|
|
|
static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am,
|
|
|
u8 *data, struct ib_device *ibdev,
|
|
|
- u8 port, u32 *resp_len)
|
|
|
+ u8 port, u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
|
|
@@ -3428,7 +3483,7 @@ static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am,
|
|
|
s64 ts;
|
|
|
int i;
|
|
|
|
|
|
- if (am != 0) {
|
|
|
+ if (am || smp_length_check(sizeof(*cong_log), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -3486,7 +3541,7 @@ static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am,
|
|
|
|
|
|
static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct ib_cc_table_attr *cc_table_attr =
|
|
|
(struct ib_cc_table_attr *)data;
|
|
@@ -3498,9 +3553,10 @@ static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
int i, j;
|
|
|
u32 sentry, eentry;
|
|
|
struct cc_state *cc_state;
|
|
|
+ u32 size = sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1);
|
|
|
|
|
|
/* sanity check n_blocks, start_block */
|
|
|
- if (n_blocks == 0 ||
|
|
|
+ if (n_blocks == 0 || smp_length_check(size, max_len) ||
|
|
|
start_block + n_blocks > ppd->cc_max_table_entries) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
@@ -3530,14 +3586,14 @@ static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
if (resp_len)
|
|
|
- *resp_len += sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1);
|
|
|
+ *resp_len += size;
|
|
|
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
|
|
|
|
static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct ib_cc_table_attr *p = (struct ib_cc_table_attr *)data;
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
@@ -3548,9 +3604,10 @@ static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
int i, j;
|
|
|
u32 sentry, eentry;
|
|
|
u16 ccti_limit;
|
|
|
+ u32 size = sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1);
|
|
|
|
|
|
/* sanity check n_blocks, start_block */
|
|
|
- if (n_blocks == 0 ||
|
|
|
+ if (n_blocks == 0 || smp_length_check(size, max_len) ||
|
|
|
start_block + n_blocks > ppd->cc_max_table_entries) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
@@ -3581,7 +3638,8 @@ static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
/* now apply the information */
|
|
|
apply_cc_state(ppd);
|
|
|
|
|
|
- return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
struct opa_led_info {
|
|
@@ -3594,7 +3652,7 @@ struct opa_led_info {
|
|
|
|
|
|
static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct hfi1_pportdata *ppd = dd->pport;
|
|
@@ -3602,7 +3660,7 @@ static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
u32 nport = OPA_AM_NPORT(am);
|
|
|
u32 is_beaconing_active;
|
|
|
|
|
|
- if (nport != 1) {
|
|
|
+ if (nport != 1 || smp_length_check(sizeof(*p), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -3624,14 +3682,14 @@ static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
|
|
|
static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
|
|
|
struct opa_led_info *p = (struct opa_led_info *)data;
|
|
|
u32 nport = OPA_AM_NPORT(am);
|
|
|
int on = !!(be32_to_cpu(p->rsvd_led_mask) & OPA_LED_MASK);
|
|
|
|
|
|
- if (nport != 1) {
|
|
|
+ if (nport != 1 || smp_length_check(sizeof(*p), max_len)) {
|
|
|
smp->status |= IB_SMP_INVALID_FIELD;
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
|
}
|
|
@@ -3641,12 +3699,13 @@ static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
|
|
|
else
|
|
|
shutdown_led_override(dd->pport);
|
|
|
|
|
|
- return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len);
|
|
|
+ return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len,
|
|
|
+ max_len);
|
|
|
}
|
|
|
|
|
|
static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am,
|
|
|
u8 *data, struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
int ret;
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
@@ -3654,71 +3713,71 @@ static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am,
|
|
|
switch (attr_id) {
|
|
|
case IB_SMP_ATTR_NODE_DESC:
|
|
|
ret = __subn_get_opa_nodedesc(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_NODE_INFO:
|
|
|
ret = __subn_get_opa_nodeinfo(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_PORT_INFO:
|
|
|
ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_PKEY_TABLE:
|
|
|
ret = __subn_get_opa_pkeytable(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SL_TO_SC_MAP:
|
|
|
ret = __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_SL_MAP:
|
|
|
ret = __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_VLT_MAP:
|
|
|
ret = __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_VLNT_MAP:
|
|
|
ret = __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_PORT_STATE_INFO:
|
|
|
ret = __subn_get_opa_psi(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE:
|
|
|
ret = __subn_get_opa_bct(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_CABLE_INFO:
|
|
|
ret = __subn_get_opa_cable_info(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_VL_ARB_TABLE:
|
|
|
ret = __subn_get_opa_vl_arb(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_CONGESTION_INFO:
|
|
|
ret = __subn_get_opa_cong_info(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING:
|
|
|
ret = __subn_get_opa_cong_setting(smp, am, data, ibdev,
|
|
|
- port, resp_len);
|
|
|
+ port, resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_HFI_CONGESTION_LOG:
|
|
|
ret = __subn_get_opa_hfi1_cong_log(smp, am, data, ibdev,
|
|
|
- port, resp_len);
|
|
|
+ port, resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE:
|
|
|
ret = __subn_get_opa_cc_table(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_LED_INFO:
|
|
|
ret = __subn_get_opa_led_info(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_SM_INFO:
|
|
|
if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED)
|
|
@@ -3736,7 +3795,7 @@ static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am,
|
|
|
|
|
|
static int subn_set_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am,
|
|
|
u8 *data, struct ib_device *ibdev, u8 port,
|
|
|
- u32 *resp_len)
|
|
|
+ u32 *resp_len, u32 max_len)
|
|
|
{
|
|
|
int ret;
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
@@ -3744,51 +3803,51 @@ static int subn_set_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am,
|
|
|
switch (attr_id) {
|
|
|
case IB_SMP_ATTR_PORT_INFO:
|
|
|
ret = __subn_set_opa_portinfo(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_PKEY_TABLE:
|
|
|
ret = __subn_set_opa_pkeytable(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SL_TO_SC_MAP:
|
|
|
ret = __subn_set_opa_sl_to_sc(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_SL_MAP:
|
|
|
ret = __subn_set_opa_sc_to_sl(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_VLT_MAP:
|
|
|
ret = __subn_set_opa_sc_to_vlt(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_SC_TO_VLNT_MAP:
|
|
|
ret = __subn_set_opa_sc_to_vlnt(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_PORT_STATE_INFO:
|
|
|
ret = __subn_set_opa_psi(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE:
|
|
|
ret = __subn_set_opa_bct(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_VL_ARB_TABLE:
|
|
|
ret = __subn_set_opa_vl_arb(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING:
|
|
|
ret = __subn_set_opa_cong_setting(smp, am, data, ibdev,
|
|
|
- port, resp_len);
|
|
|
+ port, resp_len, max_len);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE:
|
|
|
ret = __subn_set_opa_cc_table(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_LED_INFO:
|
|
|
ret = __subn_set_opa_led_info(smp, am, data, ibdev, port,
|
|
|
- resp_len);
|
|
|
+ resp_len, max_len);
|
|
|
break;
|
|
|
case IB_SMP_ATTR_SM_INFO:
|
|
|
if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED)
|
|
@@ -3844,7 +3903,10 @@ static int subn_get_opa_aggregate(struct opa_smp *smp,
|
|
|
memset(next_smp + sizeof(*agg), 0, agg_data_len);
|
|
|
|
|
|
(void)subn_get_opa_sma(agg->attr_id, smp, am, agg->data,
|
|
|
- ibdev, port, NULL);
|
|
|
+ ibdev, port, NULL, (u32)agg_data_len);
|
|
|
+
|
|
|
+ if (smp->status & IB_SMP_INVALID_FIELD)
|
|
|
+ break;
|
|
|
if (smp->status & ~IB_SMP_DIRECTION) {
|
|
|
set_aggr_error(agg);
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
@@ -3887,7 +3949,9 @@ static int subn_set_opa_aggregate(struct opa_smp *smp,
|
|
|
}
|
|
|
|
|
|
(void)subn_set_opa_sma(agg->attr_id, smp, am, agg->data,
|
|
|
- ibdev, port, NULL);
|
|
|
+ ibdev, port, NULL, (u32)agg_data_len);
|
|
|
+ if (smp->status & IB_SMP_INVALID_FIELD)
|
|
|
+ break;
|
|
|
if (smp->status & ~IB_SMP_DIRECTION) {
|
|
|
set_aggr_error(agg);
|
|
|
return reply((struct ib_mad_hdr *)smp);
|
|
@@ -3997,12 +4061,13 @@ static int process_subn_opa(struct ib_device *ibdev, int mad_flags,
|
|
|
struct opa_smp *smp = (struct opa_smp *)out_mad;
|
|
|
struct hfi1_ibport *ibp = to_iport(ibdev, port);
|
|
|
u8 *data;
|
|
|
- u32 am;
|
|
|
+ u32 am, data_size;
|
|
|
__be16 attr_id;
|
|
|
int ret;
|
|
|
|
|
|
*out_mad = *in_mad;
|
|
|
data = opa_get_smp_data(smp);
|
|
|
+ data_size = (u32)opa_get_smp_data_size(smp);
|
|
|
|
|
|
am = be32_to_cpu(smp->attr_mod);
|
|
|
attr_id = smp->attr_id;
|
|
@@ -4046,7 +4111,8 @@ static int process_subn_opa(struct ib_device *ibdev, int mad_flags,
|
|
|
default:
|
|
|
clear_opa_smp_data(smp);
|
|
|
ret = subn_get_opa_sma(attr_id, smp, am, data,
|
|
|
- ibdev, port, resp_len);
|
|
|
+ ibdev, port, resp_len,
|
|
|
+ data_size);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_AGGREGATE:
|
|
|
ret = subn_get_opa_aggregate(smp, ibdev, port,
|
|
@@ -4058,7 +4124,8 @@ static int process_subn_opa(struct ib_device *ibdev, int mad_flags,
|
|
|
switch (attr_id) {
|
|
|
default:
|
|
|
ret = subn_set_opa_sma(attr_id, smp, am, data,
|
|
|
- ibdev, port, resp_len);
|
|
|
+ ibdev, port, resp_len,
|
|
|
+ data_size);
|
|
|
break;
|
|
|
case OPA_ATTRIB_ID_AGGREGATE:
|
|
|
ret = subn_set_opa_aggregate(smp, ibdev, port,
|