aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/cm.c91
-rw-r--r--drivers/infiniband/core/ucm.c19
-rw-r--r--include/rdma/ib_cm.h23
3 files changed, 114 insertions, 19 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 86fee43502cd..490fd03766db 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -32,7 +32,7 @@
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE. 33 * SOFTWARE.
34 * 34 *
35 * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ 35 * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
36 */ 36 */
37 37
38#include <linux/completion.h> 38#include <linux/completion.h>
@@ -132,6 +132,7 @@ struct cm_id_private {
132 /* todo: use alternate port on send failure */ 132 /* todo: use alternate port on send failure */
133 struct cm_av av; 133 struct cm_av av;
134 struct cm_av alt_av; 134 struct cm_av alt_av;
135 struct ib_cm_compare_data *compare_data;
135 136
136 void *private_data; 137 void *private_data;
137 __be64 tid; 138 __be64 tid;
@@ -357,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
357 return cm_id_priv; 358 return cm_id_priv;
358} 359}
359 360
361static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
362{
363 int i;
364
365 for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
366 ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
367 ((unsigned long *) mask)[i];
368}
369
370static int cm_compare_data(struct ib_cm_compare_data *src_data,
371 struct ib_cm_compare_data *dst_data)
372{
373 u8 src[IB_CM_COMPARE_SIZE];
374 u8 dst[IB_CM_COMPARE_SIZE];
375
376 if (!src_data || !dst_data)
377 return 0;
378
379 cm_mask_copy(src, src_data->data, dst_data->mask);
380 cm_mask_copy(dst, dst_data->data, src_data->mask);
381 return memcmp(src, dst, IB_CM_COMPARE_SIZE);
382}
383
384static int cm_compare_private_data(u8 *private_data,
385 struct ib_cm_compare_data *dst_data)
386{
387 u8 src[IB_CM_COMPARE_SIZE];
388
389 if (!dst_data)
390 return 0;
391
392 cm_mask_copy(src, private_data, dst_data->mask);
393 return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
394}
395
360static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) 396static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
361{ 397{
362 struct rb_node **link = &cm.listen_service_table.rb_node; 398 struct rb_node **link = &cm.listen_service_table.rb_node;
@@ -364,14 +400,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
364 struct cm_id_private *cur_cm_id_priv; 400 struct cm_id_private *cur_cm_id_priv;
365 __be64 service_id = cm_id_priv->id.service_id; 401 __be64 service_id = cm_id_priv->id.service_id;
366 __be64 service_mask = cm_id_priv->id.service_mask; 402 __be64 service_mask = cm_id_priv->id.service_mask;
403 int data_cmp;
367 404
368 while (*link) { 405 while (*link) {
369 parent = *link; 406 parent = *link;
370 cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 407 cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
371 service_node); 408 service_node);
409 data_cmp = cm_compare_data(cm_id_priv->compare_data,
410 cur_cm_id_priv->compare_data);
372 if ((cur_cm_id_priv->id.service_mask & service_id) == 411 if ((cur_cm_id_priv->id.service_mask & service_id) ==
373 (service_mask & cur_cm_id_priv->id.service_id) && 412 (service_mask & cur_cm_id_priv->id.service_id) &&
374 (cm_id_priv->id.device == cur_cm_id_priv->id.device)) 413 (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
414 !data_cmp)
375 return cur_cm_id_priv; 415 return cur_cm_id_priv;
376 416
377 if (cm_id_priv->id.device < cur_cm_id_priv->id.device) 417 if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
@@ -380,6 +420,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
380 link = &(*link)->rb_right; 420 link = &(*link)->rb_right;
381 else if (service_id < cur_cm_id_priv->id.service_id) 421 else if (service_id < cur_cm_id_priv->id.service_id)
382 link = &(*link)->rb_left; 422 link = &(*link)->rb_left;
423 else if (service_id > cur_cm_id_priv->id.service_id)
424 link = &(*link)->rb_right;
425 else if (data_cmp < 0)
426 link = &(*link)->rb_left;
383 else 427 else
384 link = &(*link)->rb_right; 428 link = &(*link)->rb_right;
385 } 429 }
@@ -389,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
389} 433}
390 434
391static struct cm_id_private * cm_find_listen(struct ib_device *device, 435static struct cm_id_private * cm_find_listen(struct ib_device *device,
392 __be64 service_id) 436 __be64 service_id,
437 u8 *private_data)
393{ 438{
394 struct rb_node *node = cm.listen_service_table.rb_node; 439 struct rb_node *node = cm.listen_service_table.rb_node;
395 struct cm_id_private *cm_id_priv; 440 struct cm_id_private *cm_id_priv;
441 int data_cmp;
396 442
397 while (node) { 443 while (node) {
398 cm_id_priv = rb_entry(node, struct cm_id_private, service_node); 444 cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
445 data_cmp = cm_compare_private_data(private_data,
446 cm_id_priv->compare_data);
399 if ((cm_id_priv->id.service_mask & service_id) == 447 if ((cm_id_priv->id.service_mask & service_id) ==
400 cm_id_priv->id.service_id && 448 cm_id_priv->id.service_id &&
401 (cm_id_priv->id.device == device)) 449 (cm_id_priv->id.device == device) && !data_cmp)
402 return cm_id_priv; 450 return cm_id_priv;
403 451
404 if (device < cm_id_priv->id.device) 452 if (device < cm_id_priv->id.device)
@@ -407,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
407 node = node->rb_right; 455 node = node->rb_right;
408 else if (service_id < cm_id_priv->id.service_id) 456 else if (service_id < cm_id_priv->id.service_id)
409 node = node->rb_left; 457 node = node->rb_left;
458 else if (service_id > cm_id_priv->id.service_id)
459 node = node->rb_right;
460 else if (data_cmp < 0)
461 node = node->rb_left;
410 else 462 else
411 node = node->rb_right; 463 node = node->rb_right;
412 } 464 }
@@ -730,15 +782,14 @@ retest:
730 wait_for_completion(&cm_id_priv->comp); 782 wait_for_completion(&cm_id_priv->comp);
731 while ((work = cm_dequeue_work(cm_id_priv)) != NULL) 783 while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
732 cm_free_work(work); 784 cm_free_work(work);
733 if (cm_id_priv->private_data && cm_id_priv->private_data_len) 785 kfree(cm_id_priv->compare_data);
734 kfree(cm_id_priv->private_data); 786 kfree(cm_id_priv->private_data);
735 kfree(cm_id_priv); 787 kfree(cm_id_priv);
736} 788}
737EXPORT_SYMBOL(ib_destroy_cm_id); 789EXPORT_SYMBOL(ib_destroy_cm_id);
738 790
739int ib_cm_listen(struct ib_cm_id *cm_id, 791int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
740 __be64 service_id, 792 struct ib_cm_compare_data *compare_data)
741 __be64 service_mask)
742{ 793{
743 struct cm_id_private *cm_id_priv, *cur_cm_id_priv; 794 struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
744 unsigned long flags; 795 unsigned long flags;
@@ -752,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
752 return -EINVAL; 803 return -EINVAL;
753 804
754 cm_id_priv = container_of(cm_id, struct cm_id_private, id); 805 cm_id_priv = container_of(cm_id, struct cm_id_private, id);
755 BUG_ON(cm_id->state != IB_CM_IDLE); 806 if (cm_id->state != IB_CM_IDLE)
807 return -EINVAL;
808
809 if (compare_data) {
810 cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
811 GFP_KERNEL);
812 if (!cm_id_priv->compare_data)
813 return -ENOMEM;
814 cm_mask_copy(cm_id_priv->compare_data->data,
815 compare_data->data, compare_data->mask);
816 memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
817 IB_CM_COMPARE_SIZE);
818 }
756 819
757 cm_id->state = IB_CM_LISTEN; 820 cm_id->state = IB_CM_LISTEN;
758 821
@@ -769,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
769 832
770 if (cur_cm_id_priv) { 833 if (cur_cm_id_priv) {
771 cm_id->state = IB_CM_IDLE; 834 cm_id->state = IB_CM_IDLE;
835 kfree(cm_id_priv->compare_data);
836 cm_id_priv->compare_data = NULL;
772 ret = -EBUSY; 837 ret = -EBUSY;
773 } 838 }
774 return ret; 839 return ret;
@@ -1241,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1241 1306
1242 /* Find matching listen request. */ 1307 /* Find matching listen request. */
1243 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, 1308 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
1244 req_msg->service_id); 1309 req_msg->service_id,
1310 req_msg->private_data);
1245 if (!listen_cm_id_priv) { 1311 if (!listen_cm_id_priv) {
1246 spin_unlock_irqrestore(&cm.lock, flags); 1312 spin_unlock_irqrestore(&cm.lock, flags);
1247 cm_issue_rej(work->port, work->mad_recv_wc, 1313 cm_issue_rej(work->port, work->mad_recv_wc,
@@ -2654,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
2654 goto out; /* Duplicate message. */ 2720 goto out; /* Duplicate message. */
2655 } 2721 }
2656 cur_cm_id_priv = cm_find_listen(cm_id->device, 2722 cur_cm_id_priv = cm_find_listen(cm_id->device,
2657 sidr_req_msg->service_id); 2723 sidr_req_msg->service_id,
2724 sidr_req_msg->private_data);
2658 if (!cur_cm_id_priv) { 2725 if (!cur_cm_id_priv) {
2659 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 2726 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
2660 spin_unlock_irqrestore(&cm.lock, flags); 2727 spin_unlock_irqrestore(&cm.lock, flags);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index b396bf703f80..0136aee0faa7 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -648,6 +648,17 @@ out:
648 return result; 648 return result;
649} 649}
650 650
651static int ucm_validate_listen(__be64 service_id, __be64 service_mask)
652{
653 service_id &= service_mask;
654
655 if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||
656 ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))
657 return -EINVAL;
658
659 return 0;
660}
661
651static ssize_t ib_ucm_listen(struct ib_ucm_file *file, 662static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
652 const char __user *inbuf, 663 const char __user *inbuf,
653 int in_len, int out_len) 664 int in_len, int out_len)
@@ -663,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
663 if (IS_ERR(ctx)) 674 if (IS_ERR(ctx))
664 return PTR_ERR(ctx); 675 return PTR_ERR(ctx);
665 676
666 result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); 677 result = ucm_validate_listen(cmd.service_id, cmd.service_mask);
678 if (result)
679 goto out;
680
681 result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask,
682 NULL);
683out:
667 ib_ucm_ctx_put(ctx); 684 ib_ucm_ctx_put(ctx);
668 return result; 685 return result;
669} 686}
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h
index 0a9fcd59eb43..8f394f035684 100644
--- a/include/rdma/ib_cm.h
+++ b/include/rdma/ib_cm.h
@@ -32,7 +32,7 @@
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE. 33 * SOFTWARE.
34 * 34 *
35 * $Id: ib_cm.h 2730 2005-06-28 16:43:03Z sean.hefty $ 35 * $Id: ib_cm.h 4311 2005-12-05 18:42:01Z sean.hefty $
36 */ 36 */
37#if !defined(IB_CM_H) 37#if !defined(IB_CM_H)
38#define IB_CM_H 38#define IB_CM_H
@@ -102,7 +102,8 @@ enum ib_cm_data_size {
102 IB_CM_APR_INFO_LENGTH = 72, 102 IB_CM_APR_INFO_LENGTH = 72,
103 IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, 103 IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216,
104 IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, 104 IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136,
105 IB_CM_SIDR_REP_INFO_LENGTH = 72 105 IB_CM_SIDR_REP_INFO_LENGTH = 72,
106 IB_CM_COMPARE_SIZE = 64
106}; 107};
107 108
108struct ib_cm_id; 109struct ib_cm_id;
@@ -238,7 +239,6 @@ struct ib_cm_sidr_rep_event_param {
238 u32 qpn; 239 u32 qpn;
239 void *info; 240 void *info;
240 u8 info_len; 241 u8 info_len;
241
242}; 242};
243 243
244struct ib_cm_event { 244struct ib_cm_event {
@@ -317,6 +317,15 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
317 317
318#define IB_SERVICE_ID_AGN_MASK __constant_cpu_to_be64(0xFF00000000000000ULL) 318#define IB_SERVICE_ID_AGN_MASK __constant_cpu_to_be64(0xFF00000000000000ULL)
319#define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL) 319#define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL)
320#define IB_CMA_SERVICE_ID __constant_cpu_to_be64(0x0000000001000000ULL)
321#define IB_CMA_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFF000000ULL)
322#define IB_SDP_SERVICE_ID __constant_cpu_to_be64(0x0000000000010000ULL)
323#define IB_SDP_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFFFF0000ULL)
324
325struct ib_cm_compare_data {
326 u8 data[IB_CM_COMPARE_SIZE];
327 u8 mask[IB_CM_COMPARE_SIZE];
328};
320 329
321/** 330/**
322 * ib_cm_listen - Initiates listening on the specified service ID for 331 * ib_cm_listen - Initiates listening on the specified service ID for
@@ -330,10 +339,12 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
330 * range of service IDs. If set to 0, the service ID is matched 339 * range of service IDs. If set to 0, the service ID is matched
331 * exactly. This parameter is ignored if %service_id is set to 340 * exactly. This parameter is ignored if %service_id is set to
332 * IB_CM_ASSIGN_SERVICE_ID. 341 * IB_CM_ASSIGN_SERVICE_ID.
342 * @compare_data: This parameter is optional. It specifies data that must
343 * appear in the private data of a connection request for the specified
344 * listen request.
333 */ 345 */
334int ib_cm_listen(struct ib_cm_id *cm_id, 346int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
335 __be64 service_id, 347 struct ib_cm_compare_data *compare_data);
336 __be64 service_mask);
337 348
338struct ib_cm_req_param { 349struct ib_cm_req_param {
339 struct ib_sa_path_rec *primary_path; 350 struct ib_sa_path_rec *primary_path;