/*
 * Copyright (C) 2016-2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <trusty_ipc.h>
#include <uapi/err.h>

#include "caam.h"
#include "common.h"
#include "hwkey_srv_priv.h"
#include "hwrng_srv_priv.h"

#define TLOG_LVL TLOG_LVL_DEFAULT
#define TLOG_TAG "hwcrypto"
#include "tlog.h"

/*
 *  Hexdump content of memory region
 */
void _hexdump8(const void* ptr, size_t len) {
    addr_t address = (addr_t)ptr;
    size_t count;
    size_t i;

    for (count = 0; count < len; count += 16) {
        fprintf(stderr, "0x%08lx: ", address);
        for (i = 0; i < MIN(len - count, 16); i++) {
            fprintf(stderr, "0x%02hhx ", *(const uint8_t*)(address + i));
        }
        fprintf(stderr, "\n");
        address += 16;
    }
}

/*
 * Handle common unexpected port events
 */
void tipc_handle_port_errors(const uevent_t* ev) {
    if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
        (ev->event & IPC_HANDLE_POLL_HUP) ||
        (ev->event & IPC_HANDLE_POLL_MSG) ||
        (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
        /* should never happen with port handles */
        TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle);
        abort();
    }
}

/*
 * Handle common unexpected channel events
 */
void tipc_handle_chan_errors(const uevent_t* ev) {
    if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
        (ev->event & IPC_HANDLE_POLL_READY)) {
        /* close it as it is in an error state */
        TLOGE("error event (0x%x) for chan (%d)\n", ev->event, ev->handle);
        abort();
    }
}

/*
 *  Send single buf message
 */
int tipc_send_single_buf(handle_t chan, const void* buf, size_t len) {
    iovec_t iov = {
            .base = (void*)buf,
            .len = len,
    };
    ipc_msg_t msg = {
            .iov = &iov,
            .num_iov = 1,

    };
    return send_msg(chan, &msg);
}

/*
 *  Receive single buf message
 */
int tipc_recv_single_buf(handle_t chan, void* buf, size_t len) {
    int rc;
    ipc_msg_info_t msg_inf;

    rc = get_msg(chan, &msg_inf);
    if (rc)
        return rc;

    if (msg_inf.len != len) {
        /* unexpected msg size */
        rc = ERR_BAD_LEN;
    } else {
        iovec_t iov = {
                .base = buf,
                .len = len,
        };
        ipc_msg_t msg = {
                .iov = &iov,
                .num_iov = 1,
        };
        rc = read_msg(chan, msg_inf.id, 0, &msg);
    }

    put_msg(chan, msg_inf.id);
    return rc;
}

/*
 * Send message consisting of two segments (header and payload)
 */
int tipc_send_two_segments(handle_t chan,
                           const void* hdr,
                           size_t hdr_len,
                           const void* payload,
                           size_t payload_len) {
    iovec_t iovs[2] = {
            {
                    .base = (void*)hdr,
                    .len = hdr_len,
            },
            {
                    .base = (void*)payload,
                    .len = payload_len,
            },
    };
    ipc_msg_t msg = {
            .iov = iovs,
            .num_iov = countof(iovs),
    };
    return send_msg(chan, &msg);
}

/*
 * Receive message consisting of two segments (header and payload).
 */
int tipc_recv_two_segments(handle_t chan,
                           void* hdr,
                           size_t hdr_len,
                           void* payload,
                           size_t payload_len) {
    int rc;
    ipc_msg_info_t msg_inf;

    rc = get_msg(chan, &msg_inf);
    if (rc)
        return rc;

    if (msg_inf.len < hdr_len) {
        /* unexpected msg size */
        rc = ERR_BAD_LEN;
    } else {
        iovec_t iovs[2] = {{
                                   .base = hdr,
                                   .len = hdr_len,
                           },
                           {
                                   .base = payload,
                                   .len = payload_len,
                           }};
        ipc_msg_t msg = {
                .iov = iovs,
                .num_iov = countof(iovs),
        };
        rc = read_msg(chan, msg_inf.id, 0, &msg);
    }

    put_msg(chan, msg_inf.id);
    return rc;
}

/*
 *  Dispatch event
 */
static void dispatch_event(const uevent_t* ev) {
    assert(ev);

    if (ev->event == IPC_HANDLE_POLL_NONE) {
        /* not really an event, do nothing */
        TLOGI("got an empty event\n");
        return;
    }

    /* check if we have handler */
    struct tipc_event_handler* handler = ev->cookie;
    if (handler && handler->proc) {
        /* invoke it */
        handler->proc(ev, handler->priv);
        return;
    }

    /* no handler? close it */
    TLOGE("no handler for event (0x%x) with handle %d\n", ev->event,
          ev->handle);

    close(ev->handle);

    return;
}

/*
 *  Main application event loop
 */
int main(void) {
    int rc;
    uevent_t event;

    TLOGI("Initializing\n");

    rc = init_caam_env();
    if (rc != 0) {
        TLOGE("CAAM init env failed (%d)!\n", rc);
        return rc;
    }

    /* initialize service providers */
    hwrng_init_srv_provider();
    hwkey_init_srv_provider();

    TLOGI("enter main event loop\n");

    /* enter main event loop */
    while (true) {
        event.handle = INVALID_IPC_HANDLE;
        event.event = 0;
        event.cookie = NULL;

        rc = wait_any(&event, -1);
        if (rc < 0) {
            TLOGE("wait_any failed (%d)\n", rc);
            break;
        }

        if (rc == NO_ERROR) { /* got an event */
            dispatch_event(&event);
        }
    }

    return rc;
}
