diff options
-rw-r--r-- | drivers/infiniband/core/cm.c | 91 | ||||
-rw-r--r-- | drivers/infiniband/core/ucm.c | 19 | ||||
-rw-r--r-- | include/rdma/ib_cm.h | 23 |
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 | ||
361 | static 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 | |||
370 | static 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 | |||
384 | static 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 | |||
360 | static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) | 396 | static 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 | ||
391 | static struct cm_id_private * cm_find_listen(struct ib_device *device, | 435 | static 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 | } |
737 | EXPORT_SYMBOL(ib_destroy_cm_id); | 789 | EXPORT_SYMBOL(ib_destroy_cm_id); |
738 | 790 | ||
739 | int ib_cm_listen(struct ib_cm_id *cm_id, | 791 | int 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 | ||
651 | static 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 | |||
651 | static ssize_t ib_ucm_listen(struct ib_ucm_file *file, | 662 | static 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); | ||
683 | out: | ||
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 | ||
108 | struct ib_cm_id; | 109 | struct 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 | ||
244 | struct ib_cm_event { | 244 | struct 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 | |||
325 | struct 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 | */ |
334 | int ib_cm_listen(struct ib_cm_id *cm_id, | 346 | int 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 | ||
338 | struct ib_cm_req_param { | 349 | struct ib_cm_req_param { |
339 | struct ib_sa_path_rec *primary_path; | 350 | struct ib_sa_path_rec *primary_path; |