// File: /workspace/github_c_makefile_star2_O3/Arlu[P]RDMA-Hello-World/setup_ib.c
// Function: setup_ib
int setup_ib()
{
    struct ibv_device **dev_list, *ib_dev;

    srand48(getpid() * time(NULL));

    memset(&ib_res, 0, sizeof(struct IBRes));
    ib_res.size = BUFFER_SIZE;
    ib_res.buf = malloc(roundup(BUFFER_SIZE, sysconf(_SC_PAGESIZE)));
    if (!ib_res.buf) {
        perror("Couldn't allocate work buf.\n");
        return 1;
    }

    memset(ib_res.buf, 0x7b + (server_name ? 0 : 1), BUFFER_SIZE);

    // Get an IB devices list:
    dev_list = ibv_get_device_list(NULL);
    if (!dev_list)
    {
        perror("Failed to get IB devices list.\n");
        return 1;
    }

    // Get an IB device:
    ib_dev = *dev_list;
    if (!ib_dev)
    {
        perror("No IB devices found.\n");
        return 1;
    }

    // Open an IB device context:
    ib_res.ctx = ibv_open_device(*dev_list);
    if (!ib_res.ctx)
    {
        fprintf(stderr, "Couldn't get context for %s.\n", ibv_get_device_name(ib_dev));
        return 1;
    }

    // Allocate a Protection Domain:
    ib_res.pd = ibv_alloc_pd(ib_res.ctx);
    if (!ib_res.pd)
    {
        perror("Failed to allocate Protection Domain.\n");
        return 1;
    }

    // Query IB port attribute:
    if (ibv_query_port(ib_res.ctx, IB_PORT, &ib_res.port_info))
    {
        perror("Failed to query IB port information.\n");
        return 1;
    }

    // Register a Memory Region:
    ib_res.mr = ibv_reg_mr(ib_res.pd, ib_res.buf, ib_res.size,
                           IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE);
    if (!ib_res.mr)
    {
        perror("Couldn't register Memory Region.\n");
        return 1;
    }

    // Creates a Completion Queue:
    ib_res.cq = ibv_create_cq(ib_res.ctx, 2 * COUNT, NULL, NULL, 0);
    if (!ib_res.cq)
    {
        perror("Couldn't create Completion Queue.\n");
        return 1;
    }

    // Creates a Queue Pair:
    {
        struct ibv_qp_init_attr qp_init_attr = {
                .send_cq = ib_res.cq,
                .recv_cq = ib_res.cq,
                .cap = {
                        .max_send_wr = COUNT,
                        .max_recv_wr = COUNT,
                        .max_send_sge = 1,
                        .max_recv_sge = 1,
                },
                .qp_type = IBV_QPT_RC,
        };

        ib_res.qp = ibv_create_qp(ib_res.pd, &qp_init_attr);
        if (!ib_res.qp) {
            perror("Couldn't create Queue Pair.\n");
            return 1;
        }

        struct ibv_qp_attr qp_attr = {
                .qp_state        = IBV_QPS_INIT,
                .pkey_index      = 0,
                .port_num        = IB_PORT,
                .qp_access_flags = IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE
        };

        if (ibv_modify_qp(ib_res.qp, &qp_attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS)) {
            perror("Failed to modify QP to INIT.\n");
            return 1;
        }
    }

    // Get LID:
    local_dest.lid = ib_res.port_info.lid;
    if (ib_res.port_info.link_layer == IBV_LINK_LAYER_INFINIBAND && !local_dest.lid)
    {
        perror("Couldn't get LID.\n");
        return 1;
    }

    // Get QPN:
    local_dest.qpn = ib_res.qp->qp_num;

    // Set PSN:
    local_dest.psn = lrand48() & 0xffffff;

    // Get details of each side:
    if (server_name)
    {
        if (get_server_dest())
        {
            perror("Couldn't get server's details.\n");
            return 1;
        }
    }
    else
    {
        if (get_client_dest())
        {
            perror("Couldn't get client's details.\n");
            return 1;
        }
    }

    // Connect Queue Pair:
    if (connect_between_qps())
    {
        perror("Couldn't connect between client and server.\n");
        return 1;
    }

    ibv_free_device_list(dev_list);
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0xd8, %rsp
callq 0x10a0
movslq %eax, %r14
xorl %ebx, %ebx
xorl %edi, %edi
callq 0x1150
imulq %rax, %r14
movq %r14, %rdi
callq 0x11a0
xorps %xmm0, %xmm0
movups %xmm0, 0x28e7(%rip)     # 0x41d8
movups %xmm0, 0x28d0(%rip)     # 0x41c8
movups %xmm0, 0x28b9(%rip)     # 0x41b8
movups %xmm0, 0x28a2(%rip)     # 0x41a8
movups %xmm0, 0x288b(%rip)     # 0x4198
movups %xmm0, 0x2874(%rip)     # 0x4188
movq $0x0, 0x28c9(%rip) # 0x41e8
movq $0x400, 0x28c6(%rip) # imm = 0x400
movl $0x1e, %edi
callq 0x11e0
movq %rax, %r14
addq $0x3ff, %r14            # imm = 0x3FF
movl $0x1e, %edi
callq 0x11e0
movq %rax, %rcx
movq %r14, %rax
cqto
idivq %rcx
movq %rax, %r14
movl $0x1e, %edi
callq 0x11e0
imulq %rax, %r14
movq %r14, %rdi
callq 0x1160
movq %rax, 0x2875(%rip)      # 0x41e8
testq %rax, %rax
je 0x1bd5
cmpq $0x1, 0x27e4(%rip)      # 0x4168
adcl $0x7b, %ebx
movl $0x400, %edx            # imm = 0x400
movq %rax, %rdi
movl %ebx, %esi
callq 0x10e0
xorl %edi, %edi
callq 0x1240
testq %rax, %rax
je 0x1bde
movq %rax, %rbx
movq (%rax), %r14
testq %r14, %r14
je 0x1be7
movq %r14, %rdi
callq 0x1040
movq %rax, 0x27c4(%rip)      # 0x4188
testq %rax, %rax
je 0x1bf0
movq %rax, %rdi
callq 0x10d0
movq %rax, 0x27b4(%rip)      # 0x4190
testq %rax, %rax
je 0x1bfa
movq 0x279c(%rip), %rdi      # 0x4188
cmpq $-0x1, 0x140(%rdi)
jne 0x1a21
cmpq $0x288, -0x8(%rdi)      # imm = 0x288
jb 0x1a21
movq -0x140(%rdi), %rax
testq %rax, %rax
je 0x1a21
leaq 0x279d(%rip), %rdx      # 0x41b0
movl $0x34, %ecx
movl $0x1, %esi
callq *%rax
jmp 0x1a54
xorps %xmm0, %xmm0
movups %xmm0, 0x27a5(%rip)     # 0x41d0
movups %xmm0, 0x278e(%rip)     # 0x41c0
movups %xmm0, 0x2777(%rip)     # 0x41b0
movl $0x0, 0x279d(%rip)      # 0x41e0
leaq 0x2766(%rip), %rdx      # 0x41b0
movl $0x1, %esi
callq 0x11b0
testl %eax, %eax
jne 0x1c03
movq 0x272d(%rip), %rdi      # 0x4190
movq 0x277e(%rip), %rsi      # 0x41e8
movq 0x277f(%rip), %rdx      # 0x41f0
movl $0x7, %ecx
callq 0x1230
movq %rax, 0x2716(%rip)      # 0x4198
testq %rax, %rax
je 0x1c0c
movq 0x26f6(%rip), %rdi      # 0x4188
movl $0x7d0, %esi            # imm = 0x7D0
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x1090
movq %rax, 0x26f6(%rip)      # 0x41a0
testq %rax, %rax
je 0x1c15
xorl %ecx, %ecx
leaq -0x58(%rbp), %rsi
movq %rcx, (%rsi)
movq %rax, 0x8(%rsi)
movq %rax, 0x10(%rsi)
movq %rcx, 0x18(%rsi)
movaps 0x5c1(%rip), %xmm0      # 0x2090
movups %xmm0, 0x20(%rsi)
movabsq $0x200000000, %rax      # imm = 0x200000000
movq %rax, 0x30(%rsi)
movl $0x0, 0x38(%rsi)
movq 0x26a1(%rip), %rdi      # 0x4190
callq 0x1220
movq %rax, 0x26ad(%rip)      # 0x41a8
testq %rax, %rax
je 0x1c1e
movq %rax, %r14
leaq -0xe8(%rbp), %r15
movl $0x90, %edx
movq %r15, %rdi
xorl %esi, %esi
callq 0x10e0
movl $0x1, (%r15)
movl $0x6, 0x20(%r15)
movb $0x1, 0x81(%r15)
movq %r14, %rdi
movq %r15, %rsi
movl $0x39, %edx
callq 0x1050
testl %eax, %eax
jne 0x1c27
movzwl 0x267f(%rip), %eax      # 0x41d2
movzwl %ax, %eax
movl %eax, 0x2614(%rip)      # 0x4170
cmpb $0x1, 0x267b(%rip)      # 0x41de
setne %cl
testw %ax, %ax
setne %al
orb %cl, %al
je 0x1c30
movq 0x262d(%rip), %rax      # 0x41a8
movl 0x34(%rax), %eax
movl %eax, 0x25f0(%rip)      # 0x4174
callq 0x1180
andl $0xffffff, %eax         # imm = 0xFFFFFF
movl %eax, 0x25e4(%rip)      # 0x4178
cmpq $0x0, 0x25cc(%rip)      # 0x4168
je 0x1bb3
callq 0x1568
testl %eax, %eax
je 0x1bc0
leaq 0x714(%rip), %rdi       # 0x22c2
jmp 0x1c49
callq 0x16a0
testl %eax, %eax
jne 0x1c42
callq 0x17d8
testl %eax, %eax
jne 0x1c39
movq %rbx, %rdi
callq 0x10b0
xorl %eax, %eax
jmp 0x1c53
leaq 0x595(%rip), %rdi       # 0x2171
jmp 0x1c49
leaq 0x5a9(%rip), %rdi       # 0x218e
jmp 0x1c49
leaq 0x5c0(%rip), %rdi       # 0x21ae
jmp 0x1c49
movq %r14, %rdi
callq 0x12b0
jmp 0x1c4e
leaq 0x5e1(%rip), %rdi       # 0x21e2
jmp 0x1c49
leaq 0x5ff(%rip), %rdi       # 0x2209
jmp 0x1c49
leaq 0x61c(%rip), %rdi       # 0x222f
jmp 0x1c49
leaq 0x635(%rip), %rdi       # 0x2251
jmp 0x1c49
leaq 0x64f(%rip), %rdi       # 0x2274
jmp 0x1c49
leaq 0x663(%rip), %rdi       # 0x2291
jmp 0x1c49
leaq 0x678(%rip), %rdi       # 0x22af
jmp 0x1c49
leaq 0x6c2(%rip), %rdi       # 0x2302
jmp 0x1c49
leaq 0x699(%rip), %rdi       # 0x22e2
callq 0x11d0
movl $0x1, %eax
addq $0xd8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq