Skip to content

Commit 234376d

Browse files
kacperradoszewskiNordicBuilder
authored andcommitted
nrf_modem_lib: add support for SO_SENDCB
Added support for SO_SENDCB in the socket offloading layer. This socket option supported by the modem firmware mfw_nrf9151-ntn allows the user to set a callback function that will be called when a send operation is done sending data on air. In order to map the nRF socket descriptor received from the modem to the appropriate ZVFS descriptor, the latter is now also stored in the offload socket context. Signed-off-by: Kacper Radoszewski <[email protected]>
1 parent d2b9289 commit 234376d

File tree

3 files changed

+145
-17
lines changed

3 files changed

+145
-17
lines changed

lib/nrf_modem_lib/nrf9x_sockets.c

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@
4848

4949
/* Offloading context related to nRF socket. */
5050
static struct nrf_sock_ctx {
51-
int nrf_fd; /* nRF socket descriptior. */
51+
int nrf_fd; /* nRF socket descriptor. */
52+
int zvfs_fd; /* ZVFS socket descriptor. */
5253
struct k_mutex *lock; /* Mutex associated with the socket. */
5354
struct k_poll_signal poll; /* poll() signal. */
55+
struct socket_ncs_sendcb sendcb; /* Send callback. */
5456
} offload_ctx[NRF_MODEM_MAX_SOCKET_COUNT];
5557

5658
static K_MUTEX_DEFINE(ctx_lock);
@@ -62,7 +64,7 @@ static bool offload_disabled;
6264
/* TLS offloading disabled only. */
6365
static bool tls_offload_disabled;
6466

65-
static struct nrf_sock_ctx *allocate_ctx(int nrf_fd)
67+
static struct nrf_sock_ctx *allocate_ctx(int nrf_fd, int zvfs_fd)
6668
{
6769
struct nrf_sock_ctx *ctx = NULL;
6870

@@ -72,6 +74,7 @@ static struct nrf_sock_ctx *allocate_ctx(int nrf_fd)
7274
if (offload_ctx[i].nrf_fd == -1) {
7375
ctx = &offload_ctx[i];
7476
ctx->nrf_fd = nrf_fd;
77+
ctx->zvfs_fd = zvfs_fd;
7578
break;
7679
}
7780
}
@@ -87,10 +90,23 @@ static void release_ctx(struct nrf_sock_ctx *ctx)
8790

8891
ctx->nrf_fd = -1;
8992
ctx->lock = NULL;
93+
ctx->zvfs_fd = -1;
94+
memset(&ctx->sendcb, 0, sizeof(ctx->sendcb));
9095

9196
k_mutex_unlock(&ctx_lock);
9297
}
9398

99+
static struct nrf_sock_ctx *find_ctx(int fd)
100+
{
101+
for (size_t i = 0; i < ARRAY_SIZE(offload_ctx); i++) {
102+
if (offload_ctx[i].nrf_fd == fd) {
103+
return &offload_ctx[i];
104+
}
105+
}
106+
107+
return NULL;
108+
}
109+
94110
static void z_to_nrf_ipv4(const struct sockaddr *z_in,
95111
struct nrf_sockaddr_in *nrf_out)
96112
{
@@ -219,6 +235,9 @@ static int z_to_nrf_optname(int z_in_level, int z_in_optname,
219235
case SO_RAI:
220236
*nrf_out_optname = NRF_SO_RAI;
221237
break;
238+
case SO_SENDCB:
239+
*nrf_out_optname = NRF_SO_SENDCB;
240+
break;
222241
default:
223242
retval = -1;
224243
break;
@@ -377,7 +396,7 @@ static int nrf9x_socket_offload_accept(void *obj, struct sockaddr *addr,
377396
goto error;
378397
}
379398

380-
ctx = allocate_ctx(new_sd);
399+
ctx = allocate_ctx(new_sd, fd);
381400
if (ctx == NULL) {
382401
errno = ENOMEM;
383402
goto error;
@@ -475,16 +494,40 @@ static int nrf9x_socket_offload_connect(void *obj, const struct sockaddr *addr,
475494
return retval;
476495
}
477496

497+
static void sendcb(const struct nrf_modem_sendcb_params *nrf_params)
498+
{
499+
struct nrf_sock_ctx *ctx;
500+
struct socket_ncs_sendcb_params params;
501+
502+
ctx = find_ctx(nrf_params->fd);
503+
if (!ctx || !ctx->sendcb.callback) {
504+
return;
505+
}
506+
507+
/* The user is interested in the zvfs_fd, not nrf_fd. */
508+
params.fd = ctx->zvfs_fd;
509+
params.bytes_sent = nrf_params->bytes_sent;
510+
params.status = (nrf_params->status == 0) ? 0 : EAGAIN;
511+
512+
/* User callback. */
513+
ctx->sendcb.callback(&params);
514+
}
515+
478516
static int nrf9x_socket_offload_setsockopt(void *obj, int level, int optname,
479517
const void *optval, socklen_t optlen)
480518
{
481-
int sd = OBJ_TO_SD(obj);
519+
520+
struct nrf_sock_ctx *ctx = OBJ_TO_CTX(obj);
521+
int sd = ctx->nrf_fd;
482522
int retval;
483523
int nrf_level = level;
484524
int nrf_optname;
485525
struct nrf_timeval nrf_timeo = { 0 };
486526
void *nrf_optval = (void *)optval;
487527
nrf_socklen_t nrf_optlen = optlen;
528+
static struct nrf_modem_sendcb offload_sendcb = {
529+
.callback = sendcb,
530+
};
488531

489532
if ((level == SOL_SOCKET) && (optname == SO_BINDTODEVICE)) {
490533
if (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER)) {
@@ -513,6 +556,15 @@ static int nrf9x_socket_offload_setsockopt(void *obj, int level, int optname,
513556
}
514557
} else if ((level == SOL_TLS) && (optname == TLS_SESSION_CACHE)) {
515558
nrf_optlen = sizeof(int);
559+
} else if ((level == SOL_SOCKET) && (optname == SO_SENDCB)) {
560+
/* Register the user callback in the socket context. */
561+
if (optval != NULL) {
562+
ctx->sendcb = *(struct socket_ncs_sendcb *)optval;
563+
nrf_optval = &offload_sendcb;
564+
nrf_optlen = sizeof(struct socket_ncs_sendcb);
565+
} else {
566+
memset(&ctx->sendcb, 0, sizeof(ctx->sendcb));
567+
}
516568
}
517569

518570
retval = nrf_setsockopt(sd, nrf_level, nrf_optname, nrf_optval,
@@ -857,17 +909,6 @@ static int nrf9x_socket_offload_fcntl(int fd, int cmd, va_list args)
857909
return retval;
858910
}
859911

860-
static struct nrf_sock_ctx *find_ctx(int fd)
861-
{
862-
for (size_t i = 0; i < ARRAY_SIZE(offload_ctx); i++) {
863-
if (offload_ctx[i].nrf_fd == fd) {
864-
return &offload_ctx[i];
865-
}
866-
}
867-
868-
return NULL;
869-
}
870-
871912
static void pollcb(struct nrf_pollfd *pollfd)
872913
{
873914
struct nrf_sock_ctx *ctx;
@@ -1095,7 +1136,7 @@ static int nrf9x_socket_create(int family, int type, int proto)
10951136
return -1;
10961137
}
10971138

1098-
ctx = allocate_ctx(sd);
1139+
ctx = allocate_ctx(sd, fd);
10991140
if (ctx == NULL) {
11001141
errno = ENOMEM;
11011142
nrf_close(sd);

tests/lib/nrf_modem_lib/nrf9x_sockets/src/nrf9x_sockets_test.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,93 @@ void test_nrf9x_socket_offload_poll(void)
17811781
TEST_ASSERT_EQUAL(ret, 0);
17821782
}
17831783

1784+
static struct nrf_modem_sendcb *nrf_sendcb;
1785+
static int sendcb_calls;
1786+
static struct nrf_modem_sendcb_params nrf_sendcb_params = { .fd = NRF_FD };
1787+
1788+
static void sendcb(const struct socket_ncs_sendcb_params *params)
1789+
{
1790+
sendcb_calls++;
1791+
}
1792+
1793+
static int stub_nrf_setsockopt_sendcb(int fd, int level, int opt, const void *val, size_t len,
1794+
int cmock_calls)
1795+
{
1796+
TEST_ASSERT_EQUAL(NRF_FD, fd);
1797+
TEST_ASSERT_EQUAL(NRF_SOL_SOCKET, level);
1798+
TEST_ASSERT_EQUAL(NRF_SO_SENDCB, opt);
1799+
if (len > 0) {
1800+
TEST_ASSERT_EQUAL(sizeof(struct nrf_modem_sendcb), len);
1801+
} else {
1802+
TEST_ASSERT_EQUAL(0, len);
1803+
}
1804+
/* Store the nRF send callback (which wraps the user callback) */
1805+
nrf_sendcb = (struct nrf_modem_sendcb *)val;
1806+
return 0;
1807+
}
1808+
1809+
static int stub_nrf_sendto_sendcb(int socket, const void *message, size_t length, int flags,
1810+
const struct nrf_sockaddr *dest_addr, nrf_socklen_t dest_len,
1811+
int cmock_calls)
1812+
{
1813+
/* No need to verify parameters, simply call the nRF send callback, if there is one. */
1814+
if (nrf_sendcb && nrf_sendcb->callback) {
1815+
nrf_sendcb->callback(&nrf_sendcb_params);
1816+
}
1817+
1818+
return length;
1819+
}
1820+
1821+
void test_nrf9x_socket_offload_sendcb(void)
1822+
{
1823+
int ret;
1824+
int fd;
1825+
int nrf_fd = NRF_FD;
1826+
int family = AF_INET6;
1827+
int type = SOCK_STREAM;
1828+
int proto = IPPROTO_TCP;
1829+
struct socket_ncs_sendcb sendcb_opt_val = { .callback = sendcb };
1830+
uint8_t data[8] = { 1 };
1831+
size_t data_len = sizeof(data);
1832+
int flags = ZSOCK_MSG_DONTWAIT;
1833+
struct sockaddr to = { .sa_family = family };
1834+
1835+
__cmock_nrf_socket_ExpectAndReturn(NRF_AF_INET6, NRF_SOCK_STREAM, NRF_IPPROTO_TCP, nrf_fd);
1836+
1837+
fd = zsock_socket(family, type, proto);
1838+
TEST_ASSERT_EQUAL(0, fd);
1839+
1840+
__cmock_nrf_setsockopt_Stub(stub_nrf_setsockopt_sendcb);
1841+
1842+
/* Set a send callback. */
1843+
1844+
ret = zsock_setsockopt(fd, SOL_SOCKET, SO_SENDCB, &sendcb_opt_val, sizeof(sendcb_opt_val));
1845+
TEST_ASSERT_EQUAL(0, ret);
1846+
1847+
/* Skip zsock_connect, etc. since for testing we just need a working zsock_socket */
1848+
1849+
__cmock_nrf_sendto_Stub(stub_nrf_sendto_sendcb);
1850+
1851+
/* Send and confirm that the registered callback is called. */
1852+
1853+
ret = zsock_sendto(fd, data, data_len, flags, &to, 42);
1854+
TEST_ASSERT_EQUAL(8, ret);
1855+
TEST_ASSERT_EQUAL(1, sendcb_calls);
1856+
1857+
__cmock_nrf_setsockopt_Stub(stub_nrf_setsockopt_sendcb);
1858+
1859+
/* Unset the send callback. */
1860+
1861+
ret = zsock_setsockopt(fd, SOL_SOCKET, SO_SENDCB, NULL, 0);
1862+
TEST_ASSERT_EQUAL(0, ret);
1863+
1864+
/* Send and confirm that the callback is no longer called. */
1865+
1866+
ret = zsock_sendto(fd, data, data_len, flags, &to, 42);
1867+
TEST_ASSERT_EQUAL(8, ret);
1868+
TEST_ASSERT_EQUAL(1, sendcb_calls);
1869+
}
1870+
17841871
/* It is required to be added to each test. That is because unity's
17851872
* main may return nonzero, while zephyr's main currently must
17861873
* return 0 in all cases (other values are reserved).

west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ manifest:
144144
- name: nrfxlib
145145
repo-path: sdk-nrfxlib
146146
path: nrfxlib
147-
revision: 99cda52a7c257951ce08a6d1dfaba00f72d01a23
147+
revision: pull/1897/head
148148
- name: trusted-firmware-m
149149
repo-path: sdk-trusted-firmware-m
150150
path: modules/tee/tf-m/trusted-firmware-m

0 commit comments

Comments
 (0)