From: Long Li
Now we have all the code in place to support SMBD protocol negotiation with SMB
server. SMBD negotiation is defined in [MS-SMBD] 3.1.5. After negotiation, the
client and server are connected through SMBD, and they can use SMBD to transfer
data payloads.
Signed-off-by: Long Li
---
fs/cifs/cifsrdma.c | 208 +
fs/cifs/cifsrdma.h | 29
2 files changed, 237 insertions(+)
diff --git a/fs/cifs/cifsrdma.c b/fs/cifs/cifsrdma.c
index ecbc832..aa3d1a5 100644
--- a/fs/cifs/cifsrdma.c
+++ b/fs/cifs/cifsrdma.c
@@ -222,6 +222,80 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc)
mempool_free(request, request->info->request_mempool);
}
+static void dump_smbd_negotiate_resp(struct smbd_negotiate_resp *resp)
+{
+ log_rdma_event("resp message min_version %u max_version %u "
+ "negotiated_version %u credits_requested %u "
+ "credits_granted %u status %u max_readwrite_size %u "
+ "preferred_send_size %u max_receive_size %u "
+ "max_fragmented_size %u\n",
+ resp->min_version, resp->max_version, resp->negotiated_version,
+ resp->credits_requested, resp->credits_granted, resp->status,
+ resp->max_readwrite_size, resp->preferred_send_size,
+ resp->max_receive_size, resp->max_fragmented_size);
+}
+
+/* Process a negotiation response message, according to [MS-SMBD]3.1.5.7 */
+static bool process_negotiation_response(struct cifs_rdma_response *response,
int packet_length)
+{
+ struct cifs_rdma_info *info = response->info;
+ struct smbd_negotiate_resp *packet =
+ (struct smbd_negotiate_resp *) response->packet;
+
+ if (packet_length < sizeof (struct smbd_negotiate_resp)) {
+ log_rdma_event("error: packet_length=%d\n", packet_length);
+ return false;
+ }
+
+ if (le16_to_cpu(packet->negotiated_version) != 0x100) {
+ log_rdma_event("error: negotiated_version=%x\n",
+ le16_to_cpu(packet->negotiated_version));
+ return false;
+ }
+ info->protocol = le16_to_cpu(packet->negotiated_version);
+
+ if (packet->credits_requested == 0) {
+ log_rdma_event("error: credits_requested==0\n");
+ return false;
+ }
+ atomic_set(&info->receive_credit_target,
+ le16_to_cpu(packet->credits_requested));
+
+ if (packet->credits_granted == 0) {
+ log_rdma_event("error: credits_granted==0\n");
+ return false;
+ }
+ atomic_set(&info->send_credits, le16_to_cpu(packet->credits_granted));
+
+ atomic_set(&info->receive_credits, 0);
+
+ if (le32_to_cpu(packet->preferred_send_size) > info->max_receive_size) {
+ log_rdma_event("error: preferred_send_size=%d\n",
+ le32_to_cpu(packet->preferred_send_size));
+ return false;
+ }
+ info->max_receive_size = le32_to_cpu(packet->preferred_send_size);
+
+ if (le32_to_cpu(packet->max_receive_size) < 128) {
+ log_rdma_event("error: max_receive_size=%d\n",
+ le32_to_cpu(packet->max_receive_size));
+ return false;
+ }
+ info->max_send_size = min_t(int, info->max_send_size,
+ le32_to_cpu(packet->max_receive_size));
+
+ if (le32_to_cpu(packet->max_fragmented_size) < 131072) {
+ log_rdma_event("error: max_fragmented_size=%d\n",
+ le32_to_cpu(packet->max_fragmented_size));
+ return false;
+ }
+ info->max_fragmented_send_size =
le32_to_cpu(packet->max_fragmented_size);
+
+ info->max_readwrite_size = le32_to_cpu(packet->max_readwrite_size);
+
+ return true;
+}
+
/* Called from softirq, when recv is done */
static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
{
@@ -248,6 +322,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
DMA_FROM_DEVICE);
switch(response->type) {
+ case SMBD_NEGOTIATE_RESP:
+ dump_smbd_negotiate_resp(
+ (struct smbd_negotiate_resp *) response->packet);
+ info->full_packet_received = true;
+ info->negotiate_done = process_negotiation_response(response,
wc->byte_len);
+ complete(&info->negotiate_completion);
+ break;
+
case SMBD_TRANSFER_DATA:
data_transfer = (struct smbd_data_transfer *) response->packet;
atomic_dec(&info->receive_credits);
@@ -397,6 +479,85 @@ static int cifs_rdma_ia_open(
}
/*
+ * Send a negotiation request message to the peer
+ * The negotiation procedure is in [MS-SMBD] 3.1.5.2 and 3.1.5.3
+ * After negotiation, the transport is connected and ready for
+ * carrying upp