[??/many] ucon_crypto.c - simple example of the userspace acrypto usage [DIRECT ACCESS]

Evgeniy Polyakov
2005-03-07T21:21:09Z

/*
* ucon_crypto.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <asm/types.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/mman.h>

#include <linux/netlink.h>
#include <linux/types.h>
#include <linux/rtnetlink.h>

#include <arpa/inet.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#include "../connector/connector.h"

#include "crypto_def.h"
#include "crypto_conn.h"
#include "crypto_user.h"

static int need_exit;
static __u32 seq;

static int netlink_send(FILE *out, int s, struct cn_msg *msg)
{
struct nlmsghdr *nlh;
unsigned int size;
char buf[128];
int err;
struct cn_msg *m;
struct crypto_conn_data *cmd;

cmd = (struct crypto_conn_data *)(msg + 1);
size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);

nlh = (struct nlmsghdr *)buf;
nlh->nlmsg_seq = seq++;
nlh->nlmsg_pid = getpid();
nlh->nlmsg_type = NLMSG_DONE;
nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
nlh->nlmsg_flags = 0;

m = NLMSG_DATA(nlh);

printf("%s: len=%u, seq=%u, ack=%u, "
"name=%s, cmd=%02x.\n",
__func__,
msg->len, msg->seq, msg->ack,
cmd->name, cmd->cmd);

memcpy(m, msg, sizeof(*m) + msg->len);

err = send(s, nlh, size, 0);
if (err == -1)
{
fprintf(out, "Failed to send: %s [%d].\n",
strerror(errno), errno);
return err;
}
fprintf(out, "%d bytes has been sent.\n", size);

return 0;
}

static int send_cmd(FILE *out, int s, struct crypto_conn_data *cm)
{
struct cn_msg *data;
struct crypto_conn_data *m;
int size;

size = sizeof(*data) + sizeof(*m) + cm->len;

data = malloc(size);
if (!data)
return -ENOMEM;

memset(data, 0, size);

data->id.idx = 0xdead;
data->id.val = 0x0000;
data->seq = seq++;
data->ack = 0;
data->len = sizeof(*cm) + cm->len;

m = (struct crypto_conn_data *)(data + 1);
memcpy(m, cm, sizeof(*m));

memcpy(m+1, cm->data, cm->len);

return netlink_send(out, s, data);
}

static int request_stat(FILE *out, int s, char *name)
{
struct crypto_conn_data m;

memset(&m, 0, sizeof(m));

m.cmd = CRYPTO_GET_STAT;
m.len = 0;

snprintf(m.name, sizeof(m.name), "%s", name);

return send_cmd(out, s, &m);
}

static void process_stat(FILE *out, struct cn_msg *data)
{
struct crypto_device_stat *stat;
struct crypto_conn_data *m;
time_t tm;

m = (struct crypto_conn_data *)(data + 1);
stat = (struct crypto_device_stat *)(m+1);

time(&tm);
fprintf(out,
"%.24s : [%x.%x] [seq=%u, ack=%u], name=%s, cmd=%#02x, "
"sesions: completed=%llu, started=%llu, finished=%llu, kmem_failed=%llu.\n",
ctime(&tm), data->id.idx, data->id.val,
data->seq, data->ack, m->name, m->cmd,
stat->scompleted, stat->sstarted, stat->sfinished, stat->kmem_failed);
fflush(out);
}

static void dump_data(FILE *out, unsigned char *ptr)
{
int i;

fprintf(out, "UCON DATA: ");
for (i=0; i<32; ++i)
fprintf(out, "%02x ", ptr[i]);
fprintf(out, "\n");
}

static int request_crypto(FILE *out, int s, char *name)
{
void *ptr;
int size, err;
struct crypto_user usr;
struct crypto_conn_data *m;

size = 4000;
ptr = malloc(size);
if (!ptr)
{
fprintf(out, "Failed to allocate %d byte area.\n", size);
return -1;
}
memset(ptr, 0x00, size);

err = mlock(ptr, size);
if (err == -1)
{
fprintf(out, "Failed to lock %d byte area.\n", size);
free(ptr);
return -1;
}

memset(&usr, 0, sizeof(usr));

usr.operation = CRYPTO_OP_ENCRYPT;
usr.mode = CRYPTO_MODE_ECB;
usr.type = CRYPTO_TYPE_AES_128;
usr.priority = 0;

usr.src = (__u64)ptr;
usr.src_size = size;
usr.dst = (__u64)ptr;
usr.dst_size = size;

usr.pid = getpid();

usr.key_size = 0;
usr.iv_size = 0;

m = malloc(sizeof(*m) + sizeof(usr) + usr.key_size + usr.iv_size);
if (!m)
return -ENOMEM;
memset(m, 0, sizeof(m));
memcpy(m+1, &usr, sizeof(usr));

m->cmd = CRYPTO_REQUEST;
m->len = sizeof(usr);

snprintf(m->name, sizeof(m->name), "%s", name);

dump_data(out, ptr);
err = send_cmd(out, s, m);
if (err)
goto err_out_free;

fprintf(out, "Command was sent.\n");
sleep(1);
dump_data(out, ptr);

//return 0;

err_out_free:
free(m);

err = munlock(ptr, size);
if (err == -1)
{
fprintf(out, "Failed to unlock %d byte area.\n", size);
free(ptr);
return -1;
}

free(ptr);

return err;
}

int main(int argc, char *argv[])
{
int s, tmp;
char buf[128];
int len;
struct nlmsghdr *reply;
struct sockaddr_nl l_local;
struct cn_msg *data;
struct crypto_conn_data *m;
FILE *out;
struct pollfd pfd;

if (argc < 2)
out = stdout;
else {
out = fopen(argv[1], "a+");
if (!out) {
fprintf(stderr, "Unable to open %s for writing: %s\n",
argv[1], strerror(errno));
out = stdout;
}
}

memset(buf, 0, sizeof(buf));

s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_NFLOG);
if (s == -1) {
perror("socket");
return -1;
}

l_local.nl_family = AF_NETLINK;
l_local.nl_groups = 0xdead;
l_local.nl_pid = getpid();

if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
perror("bind");
close(s);
return -1;
}

pfd.fd = s;

//request_stat(s, "async_provider0");

for (len=0; len<1000; ++len)
request_crypto(out, s, "hifn0");

tmp = 0;
while (!need_exit) {

pfd.events = POLLIN;
pfd.revents = 0;
switch (poll(&pfd, 1, -1))
{
case 0:
need_exit = 1;
break;
case -1:
if (errno != EINTR)
{
need_exit = 1;
break;
}
continue;
}
if (need_exit)
break;

memset(buf, 0, sizeof(buf));
len = recv(s, buf, sizeof(buf), 0);
if (len == -1) {
perror("recv buf");
close(s);
return -1;
}
reply = (struct nlmsghdr *)buf;

switch (reply->nlmsg_type) {
case NLMSG_ERROR:
fprintf(out, "Error message received.\n");
fflush(out);
break;
case NLMSG_DONE:
data = (struct cn_msg *)NLMSG_DATA(reply);
m = (struct crypto_conn_data *)(data + 1);

switch (m->cmd)
{
case CRYPTO_GET_STAT:
process_stat(out, data);
break;
default:
break;
}

break;
default:
break;
}
}

close(s);
return 0;
}