drivers: modem: sara-r4: Improve offload_sendmsg() support
Previously, msghdr was handled by forwarding each msg_iov to offload_sendto() one by one. This is not optimal, as msg_iov payload might have been sent simultaneously which would be faster. With this commit, send_socket_data() expect payload to be formated as struct msghdr which can be used directly by both offload_sendto() and offload_sendmsg(). Signed-off-by: Xavier Chapron <xavier.chapron@stimio.fr>
This commit is contained in:
parent
6020d4ce53
commit
d66d748b71
1 changed files with 120 additions and 52 deletions
|
@ -75,7 +75,6 @@ static struct modem_pin modem_pins[] = {
|
||||||
#define MDM_CMD_CONN_TIMEOUT K_SECONDS(120)
|
#define MDM_CMD_CONN_TIMEOUT K_SECONDS(120)
|
||||||
#define MDM_REGISTRATION_TIMEOUT K_SECONDS(180)
|
#define MDM_REGISTRATION_TIMEOUT K_SECONDS(180)
|
||||||
#define MDM_PROMPT_CMD_DELAY K_MSEC(50)
|
#define MDM_PROMPT_CMD_DELAY K_MSEC(50)
|
||||||
#define MDM_SENDMSG_SLEEP K_MSEC(1)
|
|
||||||
|
|
||||||
#define MDM_MAX_DATA_LENGTH 1024
|
#define MDM_MAX_DATA_LENGTH 1024
|
||||||
#define MDM_RECV_MAX_BUF 30
|
#define MDM_RECV_MAX_BUF 30
|
||||||
|
@ -296,17 +295,41 @@ int modem_detect_apn(const char *imsi)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
MODEM_CMD_DEFINE(on_cmd_sockwrite);
|
||||||
|
|
||||||
/* send binary data via the +USO[ST/WR] commands */
|
/* send binary data via the +USO[ST/WR] commands */
|
||||||
static ssize_t send_socket_data(struct modem_socket *sock,
|
static ssize_t send_socket_data(void *obj,
|
||||||
const struct sockaddr *dst_addr,
|
const struct msghdr *msg,
|
||||||
const struct modem_cmd *handler_cmds,
|
|
||||||
size_t handler_cmds_len,
|
|
||||||
const char *buf, size_t buf_len,
|
|
||||||
k_timeout_t timeout)
|
k_timeout_t timeout)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char send_buf[sizeof("AT+USO**=#,!###.###.###.###!,#####,####\r\n")];
|
char send_buf[sizeof("AT+USO**=#,!###.###.###.###!,#####,####\r\n")];
|
||||||
uint16_t dst_port = 0U;
|
uint16_t dst_port = 0U;
|
||||||
|
struct modem_socket *sock = (struct modem_socket *)obj;
|
||||||
|
const struct modem_cmd handler_cmds[] = {
|
||||||
|
MODEM_CMD("+USOST: ", on_cmd_sockwrite, 2U, ","),
|
||||||
|
MODEM_CMD("+USOWR: ", on_cmd_sockwrite, 2U, ","),
|
||||||
|
};
|
||||||
|
struct sockaddr *dst_addr = msg->msg_name;
|
||||||
|
size_t buf_len = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||||
|
if (!msg->msg_iov[i].iov_base || msg->msg_iov[i].iov_len == 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf_len += msg->msg_iov[i].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sock->is_connected && sock->ip_proto != IPPROTO_UDP) {
|
||||||
|
errno = ENOTCONN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dst_addr && sock->ip_proto == IPPROTO_UDP) {
|
||||||
|
dst_addr = &sock->dst;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sock) {
|
if (!sock) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -347,7 +370,8 @@ static ssize_t send_socket_data(struct modem_socket *sock,
|
||||||
|
|
||||||
/* set command handlers */
|
/* set command handlers */
|
||||||
ret = modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
|
ret = modem_cmd_handler_update_cmds(&mdata.cmd_handler_data,
|
||||||
handler_cmds, handler_cmds_len,
|
handler_cmds,
|
||||||
|
ARRAY_SIZE(handler_cmds),
|
||||||
true);
|
true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -366,7 +390,15 @@ static ssize_t send_socket_data(struct modem_socket *sock,
|
||||||
k_sem_reset(&mdata.sem_response);
|
k_sem_reset(&mdata.sem_response);
|
||||||
|
|
||||||
/* Send data directly on modem iface */
|
/* Send data directly on modem iface */
|
||||||
mctx.iface.write(&mctx.iface, buf, buf_len);
|
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||||
|
int len = MIN(buf_len, msg->msg_iov[i].iov_len);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mctx.iface.write(&mctx.iface, msg->msg_iov[i].iov_base, len);
|
||||||
|
buf_len -= len;
|
||||||
|
}
|
||||||
|
|
||||||
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1456,29 +1488,18 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len,
|
||||||
int flags, const struct sockaddr *to,
|
int flags, const struct sockaddr *to,
|
||||||
socklen_t tolen)
|
socklen_t tolen)
|
||||||
{
|
{
|
||||||
int ret;
|
struct iovec msg_iov = {
|
||||||
struct modem_socket *sock = (struct modem_socket *)obj;
|
.iov_base = (void *)buf,
|
||||||
static const struct modem_cmd cmd[] = {
|
.iov_len = len,
|
||||||
MODEM_CMD("+USOST: ", on_cmd_sockwrite, 2U, ","),
|
};
|
||||||
MODEM_CMD("+USOWR: ", on_cmd_sockwrite, 2U, ","),
|
struct msghdr msg = {
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_name = (struct sockaddr *)to,
|
||||||
|
.msg_namelen = tolen,
|
||||||
|
.msg_iov = &msg_iov,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!buf || len == 0) {
|
int ret = send_socket_data(obj, &msg, MDM_CMD_TIMEOUT);
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sock->is_connected && sock->ip_proto != IPPROTO_UDP) {
|
|
||||||
errno = ENOTCONN;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!to && sock->ip_proto == IPPROTO_UDP) {
|
|
||||||
to = &sock->dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = send_socket_data(sock, to, cmd, ARRAY_SIZE(cmd), buf, len,
|
|
||||||
MDM_CMD_TIMEOUT);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
errno = -ret;
|
errno = -ret;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1528,32 +1549,79 @@ static ssize_t offload_write(void *obj, const void *buffer, size_t count)
|
||||||
static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags)
|
static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags)
|
||||||
{
|
{
|
||||||
ssize_t sent = 0;
|
ssize_t sent = 0;
|
||||||
int rc;
|
int bkp_iovec_idx;
|
||||||
|
struct iovec bkp_iovec = {0};
|
||||||
LOG_DBG("msg_iovlen:%d flags:%d", msg->msg_iovlen, flags);
|
struct msghdr crafted_msg = {
|
||||||
|
.msg_name = msg->msg_name,
|
||||||
|
.msg_namelen = msg->msg_namelen,
|
||||||
|
};
|
||||||
|
size_t full_len = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Compute the full length to be send and check for invalid values */
|
||||||
for (int i = 0; i < msg->msg_iovlen; i++) {
|
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||||
|
if (!msg->msg_iov[i].iov_base || msg->msg_iov[i].iov_len == 0) {
|
||||||
const char *buf = msg->msg_iov[i].iov_base;
|
errno = EINVAL;
|
||||||
size_t len = msg->msg_iov[i].iov_len;
|
return -1;
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
rc = offload_sendto(obj, buf, len, flags,
|
|
||||||
msg->msg_name,
|
|
||||||
msg->msg_namelen);
|
|
||||||
if (rc < 0) {
|
|
||||||
if (rc == -EAGAIN) {
|
|
||||||
k_sleep(MDM_SENDMSG_SLEEP);
|
|
||||||
} else {
|
|
||||||
sent = rc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sent += rc;
|
|
||||||
buf += rc;
|
|
||||||
len -= rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
full_len += msg->msg_iov[i].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("msg_iovlen:%d flags:%d, full_len:%d",
|
||||||
|
msg->msg_iovlen, flags, full_len);
|
||||||
|
|
||||||
|
while (full_len > sent) {
|
||||||
|
int removed = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
crafted_msg.msg_iovlen = msg->msg_iovlen;
|
||||||
|
crafted_msg.msg_iov = &msg->msg_iov[0];
|
||||||
|
|
||||||
|
bkp_iovec_idx = -1;
|
||||||
|
/* Iterate on iovec to remove the bytes already sent */
|
||||||
|
while (removed < sent) {
|
||||||
|
int to_removed = sent - removed;
|
||||||
|
|
||||||
|
if (to_removed >= msg->msg_iov[i].iov_len) {
|
||||||
|
crafted_msg.msg_iovlen -= 1;
|
||||||
|
crafted_msg.msg_iov = &msg->msg_iov[i + 1];
|
||||||
|
|
||||||
|
removed += msg->msg_iov[i].iov_len;
|
||||||
|
} else {
|
||||||
|
/* Backup msg->msg_iov[i] before "removing"
|
||||||
|
* starting bytes already send.
|
||||||
|
*/
|
||||||
|
bkp_iovec_idx = i;
|
||||||
|
bkp_iovec.iov_len = msg->msg_iov[i].iov_len;
|
||||||
|
bkp_iovec.iov_base = msg->msg_iov[i].iov_base;
|
||||||
|
|
||||||
|
/* Update msg->msg_iov[i] to "remove"
|
||||||
|
* starting bytes already send.
|
||||||
|
*/
|
||||||
|
msg->msg_iov[i].iov_len -= to_removed;
|
||||||
|
msg->msg_iov[i].iov_base = &(((uint8_t *)msg->msg_iov[i].iov_base)[to_removed]);
|
||||||
|
|
||||||
|
removed += to_removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send_socket_data(obj, &crafted_msg, MDM_CMD_TIMEOUT);
|
||||||
|
|
||||||
|
/* Restore backup iovec when necessary */
|
||||||
|
if (bkp_iovec_idx != -1) {
|
||||||
|
msg->msg_iov[bkp_iovec_idx].iov_len = bkp_iovec.iov_len;
|
||||||
|
msg->msg_iov[bkp_iovec_idx].iov_base = bkp_iovec.iov_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle send_socket_data() returned value */
|
||||||
|
if (ret < 0) {
|
||||||
|
errno = -ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sent += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ssize_t)sent;
|
return (ssize_t)sent;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue