wolfssl-examples/can-bus/common.c

259 lines
6.8 KiB
C

/* common.c
*
* Copyright (C) 2021 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL 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.
*
* wolfSSL 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "common.h"
volatile int keep_running = 1;
static isotp_wolfssl_ctx isotp_ctx;
struct can_info {
int sock;
canid_t arbitration;
canid_t remote_arbitration;
};
struct can_info can_con_info;
/* Function callback for wolfSSL to add delays to messages when a receiver
* requests it*/
void can_delay(int microseconds)
{
usleep(microseconds);
}
void sig_handle(int dummy);
/* Function callback for wolfSSL to send a CAN bus frame of up to 8 bytes */
int can_receive(struct isotp_can_data *data, void *arg, int timeout) {
int nbytes;
int ret;
struct can_info *info = ((struct can_info*)arg);
struct can_frame frame;
struct pollfd p[1];
p[0].fd = info->sock;
p[0].events = POLLIN;
/* Poll for new data */
ret = poll(p, 1, timeout);
if (ret <= 0) {
return ret;
}
/* Read in the frame data */
nbytes = read(info->sock, &frame, sizeof(struct can_frame));
if (nbytes <= 0) {
return nbytes;
}
memcpy(data->data, frame.data, frame.can_dlc);
data->length = frame.can_dlc;
return ret;
}
/* Function callback for wolfSSL to send a CAN bus frame of up to 8 bytes */
int can_send(struct isotp_can_data *data, void *arg)
{
struct can_info *info = ((struct can_info*)arg);
struct can_frame frame;
memcpy(frame.data, data->data, data->length);
frame.can_dlc = data->length;
frame.can_id = info->arbitration;
return write(info->sock, &frame, sizeof(struct can_frame));
}
/* Connect to the CAN bus */
int can_connect(const char *address, uint16_t filter)
{
struct sockaddr_can addr;
struct ifreq ifr;
/* Setup a CAN bus ID filter so that the kernel space filters out messages
* we don't need. This is faster than userspace doing it */
struct can_filter rfilter[1];
int sock = -1;
rfilter[0].can_id = filter;
rfilter[0].can_mask = 0xFFF;
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Socket open error\n");
return -1;
}
/* Set the filter */
setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
strcpy(ifr.ifr_name, address);
ioctl(sock, SIOCGIFINDEX, &ifr);
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Bind error\n");
return -1;
}
return sock;
}
void can_close()
{
close(can_con_info.sock);
}
void close_ssl(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
{
if (ssl) {
int ret = WOLFSSL_SHUTDOWN_NOT_DONE;
while (ret == WOLFSSL_SHUTDOWN_NOT_DONE) {
ret = wolfSSL_shutdown(ssl);
}
if (ret != WOLFSSL_SUCCESS) {
char buffer[ERR_MSG_LEN];
int err = wolfSSL_get_error(ssl, ret);
fprintf(stderr, "Error shutting down TLS connection: %d, %s",
err, wolfSSL_ERR_error_string(err, buffer));
return;
}
}
can_close();
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
wolfSSL_Cleanup();
}
void sig_handle(int dummy)
{
(void) dummy;
keep_running = 0;
}
int setup_connection(const char *interface, int local_id, int remote_id)
{
int sock;
struct sigaction sa = { .sa_handler = sig_handle, /* .sa_flags = 0 */ };
sigaction(SIGINT, &sa, 0);
wolfSSL_Init();
/* Connect to CAN bus provided on command line, filter out everything
* except for the remote CAN ID */
sock = can_connect(interface, remote_id);
if (sock < 1) {
return -1;
}
can_con_info.sock = sock;
can_con_info.arbitration = local_id;
return 0;
}
int setup_ssl(enum service_type type, WOLFSSL_CTX **new_ctx,
WOLFSSL_METHOD **new_method, WOLFSSL **new_ssl)
{
int ret;
WOLFSSL_CTX *ctx = NULL;
WOLFSSL_METHOD* method = NULL;
WOLFSSL* ssl = NULL;
char *receive_buffer = malloc(ISOTP_DEFAULT_BUFFER_SIZE);
if (type == SERVICE_TYPE_CLIENT) {
method = wolfTLSv1_3_client_method();
} else {
method = wolfTLSv1_3_server_method();
}
if (!method) {
fprintf(stderr, "Could not init wolfSSL method\n");
return -1;
}
ctx = wolfSSL_CTX_new(method);
if (!ctx) {
fprintf(stderr, "Could not init wolfSSL context\n");
close_ssl(NULL, NULL);
return -1;
}
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
if (type == SERVICE_TYPE_CLIENT) {
ret = wolfSSL_CTX_load_verify_locations(ctx, "client.pem", NULL);
} else {
ret = wolfSSL_CTX_use_certificate_file(ctx, "server.pem",
WOLFSSL_FILETYPE_PEM);
}
if (ret != WOLFSSL_SUCCESS) {
fprintf(stderr, "ERROR: failed to load cert, "
"please check the file.\n");
close_ssl(ctx, NULL);
return -1;
}
if (type == SERVICE_TYPE_SERVER) {
if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, "server.key",
WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) {
fprintf(stderr, "ERROR: failed to load key file, "
"please check the file.\n");
close_ssl(ctx, NULL);
return -1;
}
}
ssl = wolfSSL_new(ctx);
if (!ssl) {
fprintf(stderr, "Could not init wolfSSL\n");
close_ssl(ctx, NULL);
return -1;
}
wolfSSL_SetIO_ISOTP(ssl, &isotp_ctx, can_receive, can_send, can_delay, 0,
receive_buffer, ISOTP_DEFAULT_BUFFER_SIZE, &can_con_info);
if (type == SERVICE_TYPE_CLIENT) {
ret = wolfSSL_connect(ssl);
} else {
ret = wolfSSL_accept(ssl);
}
wolfSSL_set_using_nonblock(ssl, 1);
if (ret != WOLFSSL_SUCCESS) {
char buffer[ERR_MSG_LEN];
int err = wolfSSL_get_error(ssl, ret);
fprintf(stderr, "ERROR: failed to connect using wolfSSL: %d, %s\n",
err, wolfSSL_ERR_error_string(err, buffer));
close_ssl(ctx, ssl);
return -1;
}
*new_ctx = ctx;
*new_method = method;
*new_ssl = ssl;
printf("SSL handshake done!\n");
return 0;
}