// File: /workspace/github_c_makefile_star2_O2/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, 0x296e(%rip)     # 0x41d8
movups %xmm0, 0x2957(%rip)     # 0x41c8
movups %xmm0, 0x2940(%rip)     # 0x41b8
movups %xmm0, 0x2929(%rip)     # 0x41a8
movups %xmm0, 0x2912(%rip)     # 0x4198
movups %xmm0, 0x28fb(%rip)     # 0x4188
andq $0x0, 0x2953(%rip)      # 0x41e8
movq $0x400, 0x2950(%rip) # imm = 0x400
pushq $0x1e
popq %r14
movl %r14d, %edi
callq 0x11e0
movq %rax, %r15
addq $0x3ff, %r15            # imm = 0x3FF
movl %r14d, %edi
callq 0x11e0
movq %rax, %rcx
movq %r15, %rax
cqto
idivq %rcx
movq %rax, %r15
movl %r14d, %edi
callq 0x11e0
imulq %rax, %r15
movq %r15, %rdi
callq 0x1160
movq %rax, 0x2901(%rip)      # 0x41e8
testq %rax, %rax
je 0x1b40
cmpq $0x1, 0x2870(%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 0x1b4c
movq %rax, %rbx
movq (%rax), %r14
testq %r14, %r14
je 0x1b58
movq %r14, %rdi
callq 0x1040
movq %rax, 0x2850(%rip)      # 0x4188
testq %rax, %rax
je 0x1b61
movq %rax, %rdi
callq 0x10d0
movq %rax, 0x2840(%rip)      # 0x4190
testq %rax, %rax
je 0x1b89
movq 0x2828(%rip), %rdi      # 0x4188
cmpq $-0x1, 0x140(%rdi)
jne 0x1991
cmpq $0x288, -0x8(%rdi)      # imm = 0x288
jb 0x1991
movq -0x140(%rdi), %rax
testq %rax, %rax
je 0x1991
leaq 0x2829(%rip), %rdx      # 0x41b0
pushq $0x1
popq %rsi
pushq $0x34
popq %rcx
callq *%rax
jmp 0x19bf
xorps %xmm0, %xmm0
movups %xmm0, 0x2835(%rip)     # 0x41d0
movups %xmm0, 0x281e(%rip)     # 0x41c0
movups %xmm0, 0x2807(%rip)     # 0x41b0
andl $0x0, 0x2830(%rip)      # 0x41e0
leaq 0x27f9(%rip), %rdx      # 0x41b0
pushq $0x1
popq %rsi
callq 0x11b0
testl %eax, %eax
jne 0x1b92
movq 0x27c2(%rip), %rdi      # 0x4190
movq 0x2813(%rip), %rsi      # 0x41e8
movq 0x2814(%rip), %rdx      # 0x41f0
pushq $0x7
popq %rcx
callq 0x1230
movq %rax, 0x27ad(%rip)      # 0x4198
testq %rax, %rax
je 0x1b9b
movq 0x278d(%rip), %rdi      # 0x4188
movl $0x7d0, %esi            # imm = 0x7D0
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x1090
movq %rax, 0x278d(%rip)      # 0x41a0
testq %rax, %rax
je 0x1ba4
leaq -0x58(%rbp), %rsi
andq $0x0, (%rsi)
movq %rax, 0x8(%rsi)
movq %rax, 0x10(%rsi)
andq $0x0, 0x18(%rsi)
movaps 0x658(%rip), %xmm0      # 0x2090
movups %xmm0, 0x20(%rsi)
movabsq $0x200000000, %rax      # imm = 0x200000000
movq %rax, 0x30(%rsi)
andl $0x0, 0x38(%rsi)
movq 0x273b(%rip), %rdi      # 0x4190
callq 0x1220
movq %rax, 0x2747(%rip)      # 0x41a8
testq %rax, %rax
je 0x1bad
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)
pushq $0x39
popq %rdx
movq %r14, %rdi
movq %r15, %rsi
callq 0x1050
testl %eax, %eax
jne 0x1bb6
movzwl 0x271b(%rip), %eax      # 0x41d2
movzwl %ax, %eax
movl %eax, 0x26b0(%rip)      # 0x4170
cmpb $0x1, 0x2717(%rip)      # 0x41de
setne %cl
testw %ax, %ax
setne %al
orb %cl, %al
je 0x1bbf
movq 0x26c9(%rip), %rax      # 0x41a8
movl 0x34(%rax), %eax
movl %eax, 0x268c(%rip)      # 0x4174
callq 0x1180
andl $0xffffff, %eax         # imm = 0xFFFFFF
movl %eax, 0x2680(%rip)      # 0x4178
cmpq $0x0, 0x2668(%rip)      # 0x4168
je 0x1b17
callq 0x14f0
testl %eax, %eax
je 0x1b24
leaq 0x7b0(%rip), %rdi       # 0x22c2
jmp 0x1bd8
callq 0x1625
testl %eax, %eax
jne 0x1bd1
callq 0x1753
testl %eax, %eax
jne 0x1bc8
movq %rbx, %rdi
callq 0x10b0
xorl %eax, %eax
jmp 0x1be0
leaq 0x62a(%rip), %rdi       # 0x2171
jmp 0x1bd8
leaq 0x63b(%rip), %rdi       # 0x218e
jmp 0x1bd8
leaq 0x64f(%rip), %rdi       # 0x21ae
jmp 0x1bd8
movq 0x2490(%rip), %rax      # 0x3ff8
movq (%rax), %rbx
movq %r14, %rdi
callq 0x1060
leaq 0x64a(%rip), %rsi       # 0x21c4
movq %rbx, %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x1120
jmp 0x1bdd
leaq 0x652(%rip), %rdi       # 0x21e2
jmp 0x1bd8
leaq 0x670(%rip), %rdi       # 0x2209
jmp 0x1bd8
leaq 0x68d(%rip), %rdi       # 0x222f
jmp 0x1bd8
leaq 0x6a6(%rip), %rdi       # 0x2251
jmp 0x1bd8
leaq 0x6c0(%rip), %rdi       # 0x2274
jmp 0x1bd8
leaq 0x6d4(%rip), %rdi       # 0x2291
jmp 0x1bd8
leaq 0x6e9(%rip), %rdi       # 0x22af
jmp 0x1bd8
leaq 0x733(%rip), %rdi       # 0x2302
jmp 0x1bd8
leaq 0x70a(%rip), %rdi       # 0x22e2
callq 0x11d0
pushq $0x1
popq %rax
addq $0xd8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq