summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/gpxe/ib_mad.h5
-rw-r--r--src/net/infiniband/ib_cm.c28
-rw-r--r--src/net/infiniband/ib_cmrc.c3
3 files changed, 32 insertions, 4 deletions
diff --git a/src/include/gpxe/ib_mad.h b/src/include/gpxe/ib_mad.h
index 54d0a2af..8b497183 100644
--- a/src/include/gpxe/ib_mad.h
+++ b/src/include/gpxe/ib_mad.h
@@ -402,6 +402,11 @@ struct ib_cm_connect_reject {
uint8_t private_data[148];
} __attribute__ (( packed ));
+/** CM rejection reasons */
+#define IB_CM_REJECT_BAD_SERVICE_ID 8
+#define IB_CM_REJECT_STALE_CONN 10
+#define IB_CM_REJECT_CONSUMER 28
+
/** A communication management connection reply
*
* Defined in section 12.6.8 of the IBA.
diff --git a/src/net/infiniband/ib_cm.c b/src/net/infiniband/ib_cm.c
index 859d56f2..30a3691f 100644
--- a/src/net/infiniband/ib_cm.c
+++ b/src/net/infiniband/ib_cm.c
@@ -123,6 +123,25 @@ struct ib_mad_agent ib_cm_agent[] __ib_mad_agent = {
};
/**
+ * Convert connection rejection reason to return status code
+ *
+ * @v reason Rejection reason (in network byte order)
+ * @ret rc Return status code
+ */
+static int ib_cm_rejection_reason_to_rc ( uint16_t reason ) {
+ switch ( reason ) {
+ case htons ( IB_CM_REJECT_BAD_SERVICE_ID ) :
+ return -ENODEV;
+ case htons ( IB_CM_REJECT_STALE_CONN ) :
+ return -EALREADY;
+ case htons ( IB_CM_REJECT_CONSUMER ) :
+ return -ENOTTY;
+ default:
+ return -EPERM;
+ }
+}
+
+/**
* Handle connection request transaction completion
*
* @v ibdev Infiniband device
@@ -189,9 +208,12 @@ static void ib_cm_req_complete ( struct ib_device *ibdev,
/* Extract fields */
DBGC ( conn, "CM %p connection rejected (reason %d)\n",
conn, ntohs ( connect_rej->reason ) );
- private_data = &connect_rej->private_data;
- private_data_len = sizeof ( connect_rej->private_data );
- rc = -ENOTCONN;
+ /* Private data is valid only for a Consumer Reject */
+ if ( connect_rej->reason == htons ( IB_CM_REJECT_CONSUMER ) ) {
+ private_data = &connect_rej->private_data;
+ private_data_len = sizeof (connect_rej->private_data);
+ }
+ rc = ib_cm_rejection_reason_to_rc ( connect_rej->reason );
break;
default:
diff --git a/src/net/infiniband/ib_cmrc.c b/src/net/infiniband/ib_cmrc.c
index 7ec96313..2d648115 100644
--- a/src/net/infiniband/ib_cmrc.c
+++ b/src/net/infiniband/ib_cmrc.c
@@ -172,7 +172,8 @@ static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
/* Pass up any private data */
DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
- if ( ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
+ if ( private_data &&
+ ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
private_data_len ) ) != 0 ) {
DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
cmrc, strerror ( rc_xfer ) );