aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/user_mad.c
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2006-07-20 04:25:50 -0400
committerRoland Dreier <rolandd@cisco.com>2006-07-24 12:18:07 -0400
commit2527e681fd4fd4231c2e04f09d7b04d3cab8eefe (patch)
treec9c4fe05d04bcad941505f9e8d1c3903d9501f6b /drivers/infiniband/core/user_mad.c
parent16c59419a09f0140a07a1828d6a45656265e07c7 (diff)
IB/mad: Validate MADs for spec compliance
Validate MADs sent by userspace clients for spec compliance with C13-18.1.1 (prevent duplicate requests and responses sent on the same port). Without this, RMPP transactions get aborted because of duplicate packets. This patch is similar to that provided by Jack Morgenstein. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/user_mad.c')
-rw-r--r--drivers/infiniband/core/user_mad.c87
1 files changed, 76 insertions, 11 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index afe70a549c2f..1273f8807e84 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -112,8 +112,10 @@ struct ib_umad_device {
112struct ib_umad_file { 112struct ib_umad_file {
113 struct ib_umad_port *port; 113 struct ib_umad_port *port;
114 struct list_head recv_list; 114 struct list_head recv_list;
115 struct list_head send_list;
115 struct list_head port_list; 116 struct list_head port_list;
116 spinlock_t recv_lock; 117 spinlock_t recv_lock;
118 spinlock_t send_lock;
117 wait_queue_head_t recv_wait; 119 wait_queue_head_t recv_wait;
118 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; 120 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
119 int agents_dead; 121 int agents_dead;
@@ -177,12 +179,21 @@ static int queue_packet(struct ib_umad_file *file,
177 return ret; 179 return ret;
178} 180}
179 181
182static void dequeue_send(struct ib_umad_file *file,
183 struct ib_umad_packet *packet)
184 {
185 spin_lock_irq(&file->send_lock);
186 list_del(&packet->list);
187 spin_unlock_irq(&file->send_lock);
188 }
189
180static void send_handler(struct ib_mad_agent *agent, 190static void send_handler(struct ib_mad_agent *agent,
181 struct ib_mad_send_wc *send_wc) 191 struct ib_mad_send_wc *send_wc)
182{ 192{
183 struct ib_umad_file *file = agent->context; 193 struct ib_umad_file *file = agent->context;
184 struct ib_umad_packet *packet = send_wc->send_buf->context[0]; 194 struct ib_umad_packet *packet = send_wc->send_buf->context[0];
185 195
196 dequeue_send(file, packet);
186 ib_destroy_ah(packet->msg->ah); 197 ib_destroy_ah(packet->msg->ah);
187 ib_free_send_mad(packet->msg); 198 ib_free_send_mad(packet->msg);
188 199
@@ -370,6 +381,51 @@ static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
370 return 0; 381 return 0;
371} 382}
372 383
384static int same_destination(struct ib_user_mad_hdr *hdr1,
385 struct ib_user_mad_hdr *hdr2)
386{
387 if (!hdr1->grh_present && !hdr2->grh_present)
388 return (hdr1->lid == hdr2->lid);
389
390 if (hdr1->grh_present && hdr2->grh_present)
391 return !memcmp(hdr1->gid, hdr2->gid, 16);
392
393 return 0;
394}
395
396static int is_duplicate(struct ib_umad_file *file,
397 struct ib_umad_packet *packet)
398{
399 struct ib_umad_packet *sent_packet;
400 struct ib_mad_hdr *sent_hdr, *hdr;
401
402 hdr = (struct ib_mad_hdr *) packet->mad.data;
403 list_for_each_entry(sent_packet, &file->send_list, list) {
404 sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data;
405
406 if ((hdr->tid != sent_hdr->tid) ||
407 (hdr->mgmt_class != sent_hdr->mgmt_class))
408 continue;
409
410 /*
411 * No need to be overly clever here. If two new operations have
412 * the same TID, reject the second as a duplicate. This is more
413 * restrictive than required by the spec.
414 */
415 if (!ib_response_mad((struct ib_mad *) hdr)) {
416 if (!ib_response_mad((struct ib_mad *) sent_hdr))
417 return 1;
418 continue;
419 } else if (!ib_response_mad((struct ib_mad *) sent_hdr))
420 continue;
421
422 if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr))
423 return 1;
424 }
425
426 return 0;
427}
428
373static ssize_t ib_umad_write(struct file *filp, const char __user *buf, 429static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
374 size_t count, loff_t *pos) 430 size_t count, loff_t *pos)
375{ 431{
@@ -379,7 +435,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
379 struct ib_ah_attr ah_attr; 435 struct ib_ah_attr ah_attr;
380 struct ib_ah *ah; 436 struct ib_ah *ah;
381 struct ib_rmpp_mad *rmpp_mad; 437 struct ib_rmpp_mad *rmpp_mad;
382 u8 method;
383 __be64 *tid; 438 __be64 *tid;
384 int ret, data_len, hdr_len, copy_offset, rmpp_active; 439 int ret, data_len, hdr_len, copy_offset, rmpp_active;
385 440
@@ -473,28 +528,36 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
473 } 528 }
474 529
475 /* 530 /*
476 * If userspace is generating a request that will generate a 531 * Set the high-order part of the transaction ID to make MADs from
477 * response, we need to make sure the high-order part of the 532 * different agents unique, and allow routing responses back to the
478 * transaction ID matches the agent being used to send the 533 * original requestor.
479 * MAD.
480 */ 534 */
481 method = ((struct ib_mad_hdr *) packet->msg->mad)->method; 535 if (!ib_response_mad(packet->msg->mad)) {
482
483 if (!(method & IB_MGMT_METHOD_RESP) &&
484 method != IB_MGMT_METHOD_TRAP_REPRESS &&
485 method != IB_MGMT_METHOD_SEND) {
486 tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; 536 tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
487 *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | 537 *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
488 (be64_to_cpup(tid) & 0xffffffff)); 538 (be64_to_cpup(tid) & 0xffffffff));
539 rmpp_mad->mad_hdr.tid = *tid;
540 }
541
542 spin_lock_irq(&file->send_lock);
543 ret = is_duplicate(file, packet);
544 if (!ret)
545 list_add_tail(&packet->list, &file->send_list);
546 spin_unlock_irq(&file->send_lock);
547 if (ret) {
548 ret = -EINVAL;
549 goto err_msg;
489 } 550 }
490 551
491 ret = ib_post_send_mad(packet->msg, NULL); 552 ret = ib_post_send_mad(packet->msg, NULL);
492 if (ret) 553 if (ret)
493 goto err_msg; 554 goto err_send;
494 555
495 up_read(&file->port->mutex); 556 up_read(&file->port->mutex);
496 return count; 557 return count;
497 558
559err_send:
560 dequeue_send(file, packet);
498err_msg: 561err_msg:
499 ib_free_send_mad(packet->msg); 562 ib_free_send_mad(packet->msg);
500err_ah: 563err_ah:
@@ -657,7 +720,9 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
657 } 720 }
658 721
659 spin_lock_init(&file->recv_lock); 722 spin_lock_init(&file->recv_lock);
723 spin_lock_init(&file->send_lock);
660 INIT_LIST_HEAD(&file->recv_list); 724 INIT_LIST_HEAD(&file->recv_list);
725 INIT_LIST_HEAD(&file->send_list);
661 init_waitqueue_head(&file->recv_wait); 726 init_waitqueue_head(&file->recv_wait);
662 727
663 file->port = port; 728 file->port = port;