Skip to content

Commit

Permalink
crypto: Replace old netlink helper functions with netlink contexts
Browse files Browse the repository at this point in the history
Finish refactoring of netlink helper functions for generic use
and replace the very limited netlink send/receive functions
used by the crypto tests with the new context-based helpers.

Reviewed-by: Petr Vorel <[email protected]>
Signed-off-by: Martin Doucha <[email protected]>
  • Loading branch information
mdoucha authored and pevik committed Nov 14, 2023
1 parent d6442cc commit e1301ed
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 377 deletions.
4 changes: 2 additions & 2 deletions doc/C-Test-Network-API.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ static void setup(void)
3 Netlink API
-------------
+#include "tst_rtnetlink.h"+
+#include "tst_netlink.h"+
The netlink library provides helper functions for constructing and sending
arbitrary messages and parsing kernel responses.
Expand Down Expand Up @@ -443,7 +443,7 @@ Example Usage
#include <arpa/inet.h>
#include "tst_test.h"
#include "tst_rtnetlink.h"
#include "tst_netlink.h"
#include "tst_netdevice.h"
...
Expand Down
69 changes: 7 additions & 62 deletions include/tst_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,67 +13,12 @@
#define TST_CRYPTO_H

#include "lapi/cryptouser.h"

/**
* A reference to a crypto session and associated state.
*
* Holds state relevant to a netlink crypto connection. The seq_num is used
* to tag each message sent to the netlink layer and is automatically
* incremented by the tst_crypto_ functions. When the netlink layer sends a
* response (ack) it will use the sequences number from the request.
*
* Some functions, such as delete ALG, may return EBUSY in which case it is
* safe to retry them. The retries field allows you to set the number of
* times this should be done. If set to zero the operation will only be tried
* once. For operations which do not return EBUSY, the field is ignored.
*
* Use TST_CRYPTO_SESSION_INIT to statically initialize this struct with sane
* defaults.
*/
struct tst_crypto_session {
/** File descriptor for the netlink socket */
int fd;
/** A sequence number used to identify responses from the kernel. */
uint32_t seq_num;
/** Number of times some operations will be retried. */
uint32_t retries;
};

/**
* Default static definition of tst_crypto_session.
*
* @relates tst_crypto_session
*/
#define TST_CRYPTO_SESSION_INIT {\
.fd = 0, \
.seq_num = 0, \
.retries = 1000 \
}

/**
* Creates a crypto session.
*
* @relates tst_crypto_session
* @param ses Session structure to use, it can be uninitialized.
*
* If some necessary feature is missing then it will call tst_brk() with
* TCONF, for any other error it will use TBROK.
*/
void tst_crypto_open(struct tst_crypto_session *ses);

/**
* Close a crypto session.
*
* @relates tst_crypto_session
* @param ses The session to close.
*/
void tst_crypto_close(struct tst_crypto_session *ses);
#include "tst_netlink.h"

/**
* Add a crypto algorithm to a session.
*
* @relates tst_crypto_session
* @param ses An open session.
* @param ctx Initialized netlink context
* @param alg The crypto algorithm or module to add.
*
* This requests a new crypto algorithm/engine/module to be initialized by the
Expand All @@ -84,15 +29,15 @@ void tst_crypto_close(struct tst_crypto_session *ses);
* @return On success it will return 0 otherwise it will return an inverted
* error code from the crypto layer.
*/
int tst_crypto_add_alg(struct tst_crypto_session *ses,
int tst_crypto_add_alg(struct tst_netlink_context *ctx,
const struct crypto_user_alg *alg);

/**
* Delete a crypto algorithm from a session.
*
* @relates tst_crypto_session
* @param ses An open session.
* @param ctx Initialized netlink context
* @param alg The crypto algorithm to delete.
* @param retries Number of retries before giving up. Recommended value: 1000
*
* Request that the kernel remove an existing crypto algorithm. This behaves
* in a similar way to tst_crypto_add_alg() except that it is the inverse
Expand All @@ -106,7 +51,7 @@ int tst_crypto_add_alg(struct tst_crypto_session *ses,
* library, you don't need to log this error as it will already have
* been printed by tst_brk().
*/
int tst_crypto_del_alg(struct tst_crypto_session *ses,
const struct crypto_user_alg *alg);
int tst_crypto_del_alg(struct tst_netlink_context *ctx,
const struct crypto_user_alg *alg, unsigned int retries);

#endif /* TST_CRYPTO_H */
2 changes: 1 addition & 1 deletion include/tst_netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#ifndef TST_NETDEVICE_H
#define TST_NETDEVICE_H

#include "tst_rtnetlink.h"
#include "tst_netlink.h"

/* Find device index for given network interface name. */
int tst_netdev_index_by_name(const char *file, const int lineno,
Expand Down
171 changes: 97 additions & 74 deletions include/tst_netlink.h
Original file line number Diff line number Diff line change
@@ -1,88 +1,111 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (c) 2018 Richard Palethorpe <[email protected]>
*/

/**
* @file tst_netlink.h
*
* Library for communicating with the kernel over the netlink interface.
* Copyright (c) 2021 Linux Test Project
*/

#ifndef TST_NETLINK_H
#define TST_NETLINK_H

#include <linux/netlink.h>

#ifndef NETLINK_CRYPTO
/**
* The netlink-crypto socket protocol.
struct tst_netlink_context;

struct tst_rtnl_attr_list {
unsigned short type;
const void *data;
ssize_t len;
const struct tst_rtnl_attr_list *sublist;
};

struct tst_netlink_message {
struct nlmsghdr *header;
struct nlmsgerr *err;
void *payload;
size_t payload_size;
};

extern int tst_netlink_errno;

/* Open a netlink socket */
struct tst_netlink_context *tst_netlink_create_context(const char *file,
const int lineno, int protocol);
#define NETLINK_CREATE_CONTEXT(protocol) \
tst_netlink_create_context(__FILE__, __LINE__, (protocol))

/* Free a tst_netlink_message array returned by tst_netlink_recv() */
void tst_netlink_free_message(struct tst_netlink_message *msg);
#define NETLINK_FREE_MESSAGE tst_netlink_free_message

/* Close netlink socket */
void tst_netlink_destroy_context(const char *file, const int lineno,
struct tst_netlink_context *ctx);
#define NETLINK_DESTROY_CONTEXT(ctx) \
tst_netlink_destroy_context(__FILE__, __LINE__, (ctx))

/* Send all messages in given buffer */
int tst_netlink_send(const char *file, const int lineno,
struct tst_netlink_context *ctx);
#define NETLINK_SEND(ctx) tst_netlink_send(__FILE__, __LINE__, (ctx))

/* Send all messages in given buffer and validate kernel response */
int tst_netlink_send_validate(const char *file, const int lineno,
struct tst_netlink_context *ctx);
#define NETLINK_SEND_VALIDATE(ctx) \
tst_netlink_send_validate(__FILE__, __LINE__, (ctx))

/* Wait until data is available for reading from the netlink socket */
int tst_netlink_wait(struct tst_netlink_context *ctx);
#define NETLINK_WAIT tst_netlink_wait

/*
* Read from netlink socket and return an array of partially parsed messages.
* header == NULL indicates end of array.
*/
#define NETLINK_CRYPTO 21
#endif

/** @private */
static inline ssize_t safe_netlink_send(const char *file, const int lineno,
int fd, const struct nlmsghdr *nh,
const void *payload)
{
struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
struct iovec iov[2] = {
{(struct nlmsghdr *)nh, sizeof(*nh)},
{(void *)payload, nh->nlmsg_len - sizeof(*nh)}
};
struct msghdr msg = {
.msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = iov,
.msg_iovlen = 2
};

return safe_sendmsg(file, lineno, nh->nlmsg_len, fd, &msg, 0);
}

/**
* Sends a netlink message using safe_sendmsg().
*
* @param fd netlink socket file descriptor.
* @param nl_header netlink header structure describing the message.
* @param payload an opaque object containing the message data.
*
* You should set the message length, type and flags to appropriate values
* within the nl_header object. See lib/tst_crypto.c for an example.
*
* @return The number of bytes sent.
struct tst_netlink_message *tst_netlink_recv(const char *file, const int lineno,
struct tst_netlink_context *ctx);
#define NETLINK_RECV(ctx) tst_netlink_recv(__FILE__, __LINE__, (ctx))

/* Add new message to buffer */
int tst_netlink_add_message(const char *file, const int lineno,
struct tst_netlink_context *ctx, const struct nlmsghdr *header,
const void *payload, size_t payload_size);
#define NETLINK_ADD_MESSAGE(ctx, header, payload, psize) \
tst_netlink_add_message(__FILE__, __LINE__, (ctx), (header), \
(payload), (psize))

/* Add arbitrary attribute to last message */
int tst_rtnl_add_attr(const char *file, const int lineno,
struct tst_netlink_context *ctx, unsigned short type, const void *data,
unsigned short len);
#define RTNL_ADD_ATTR(ctx, type, data, len) \
tst_rtnl_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len))

/* Add string attribute to last message */
int tst_rtnl_add_attr_string(const char *file, const int lineno,
struct tst_netlink_context *ctx, unsigned short type, const char *data);
#define RTNL_ADD_ATTR_STRING(ctx, type, data) \
tst_rtnl_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data))

/*
* Add list of arbitrary attributes to last message. The list is terminated
* by attribute with negative length. Nested sublists are supported.
*/
#define SAFE_NETLINK_SEND(fd, nl_header, payload) \
safe_netlink_send(__FILE__, __LINE__, fd, nl_header, payload)

/** @private */
static inline ssize_t safe_netlink_recv(const char *file, const int lineno,
int fd, char *nl_headers_buf,
size_t buf_len)
{
struct iovec iov = { nl_headers_buf, buf_len };
struct sockaddr_nl sa;
struct msghdr msg = {
.msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
.msg_iovlen = 1
};

return safe_recvmsg(file, lineno, 0, fd, &msg, 0);
}

/**
* Receives a netlink message using safe_recvmsg().
*
* @param fd netlink socket file descriptor.
* @param nl_header_buf buffer to contain the received netlink header structure.
* @param buf_len The length of the header buffer. Must be greater than the page
* size.
int tst_rtnl_add_attr_list(const char *file, const int lineno,
struct tst_netlink_context *ctx, const struct tst_rtnl_attr_list *list);
#define RTNL_ADD_ATTR_LIST(ctx, list) \
tst_rtnl_add_attr_list(__FILE__, __LINE__, (ctx), (list))

/* Check that all sent messages with NLM_F_ACK flag have been acked without
* error. Usage:
*
* @return The number of bytes received.
* tst_netlink_send(ctx);
* tst_netlink_wait(ctx);
* response = tst_netlink_recv(ctx);
* if (!tst_netlink_check_acks(ctx, response)) { ... }
* tst_netlink_free_message(response);
*/
#define SAFE_NETLINK_RECV(fd, nl_header_buf, buf_len) \
safe_netlink_recv(__FILE__, __LINE__, fd, nl_header_buf, buf_len)
int tst_netlink_check_acks(const char *file, const int lineno,
struct tst_netlink_context *ctx, struct tst_netlink_message *response);
#define NETLINK_CHECK_ACKS(ctx, response) \
tst_netlink_check_acks(__FILE__, __LINE__, (ctx), (response))

#endif /* TST_NETLINK_H */
Loading

0 comments on commit e1301ed

Please sign in to comment.