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 @@ -122,6 +122,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 * @@ -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 ) );