/* * proto.c * * (C) 2019 by Sylvain Munaut * * All Rights Reserved * * SPDX-License-Identifier: LGPL-3.0-or-later * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 3 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 Lesser General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #include #include #include #include "log.h" const struct value_string osmo_e1dp_msg_type_names[] = { { E1DP_CMD_INTF_QUERY, "CMD_INTF_QUERY" }, { E1DP_CMD_LINE_QUERY, "CMD_LINE_QUERY" }, { E1DP_CMD_TS_QUERY, "CMD_TS_QUERY" }, { E1DP_CMD_TS_OPEN, "CMD_TS_OPEN" }, { E1DP_EVT_TYPE, "EVT_TYPE" }, { E1DP_RESP_TYPE, "RESP_TYPE" }, { E1DP_ERR_TYPE, "ERR_TYPE" }, { 0, NULL } }; const struct value_string osmo_e1dp_line_mode_names[] = { { E1DP_LMODE_OFF, "OFF" }, { E1DP_LMODE_CHANNELIZED, "CHANNELIZED" }, { E1DP_LMODE_SUPERCHANNEL, "SUPERCHANNEL" }, { 0, NULL } }; const struct value_string osmo_e1dp_ts_mode_names[] = { { E1DP_TSMODE_OFF, "OFF" }, { E1DP_TSMODE_RAW, "RAW" }, { E1DP_TSMODE_HDLCFCS, "HDLC-FCS" }, { 0, NULL } }; struct msgb * osmo_e1dp_recv(struct osmo_fd *ofd, int *fd) { struct msgb *msgb; struct osmo_e1dp_msg_hdr *hdr; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; char cms[CMSG_SPACE(sizeof(int))]; int rc; msgb = msgb_alloc(E1DP_MAX_LEN, "e1d proto rx message"); memset(&msg, 0x00, sizeof(msg)); iov.iov_base = msgb->data; iov.iov_len = E1DP_MAX_LEN; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = (caddr_t) cms; msg.msg_controllen = sizeof(cms); rc = recvmsg(ofd->fd, &msg, MSG_WAITALL | MSG_CMSG_CLOEXEC); if (rc == 0) goto err; if (rc < (int)sizeof(struct osmo_e1dp_msg_hdr)) { LOGP(DE1D, LOGL_ERROR, "Failed to read packet header.\n"); goto err; } msgb->l1h = msgb_put(msgb, sizeof(struct osmo_e1dp_msg_hdr)); hdr = msgb_l1(msgb); if ((hdr->magic != E1DP_MAGIC) || (hdr->len < sizeof(struct osmo_e1dp_msg_hdr))) { LOGP(DE1D, LOGL_ERROR, "Invalid packet header.\n"); goto err; } if (hdr->len > sizeof(struct osmo_e1dp_msg_hdr)) msgb->l2h = msgb_put(msgb, hdr->len - sizeof(struct osmo_e1dp_msg_hdr)); else msgb->l2h = msgb->tail; if (fd) { cmsg = CMSG_FIRSTHDR(&msg); if (cmsg) { memmove(fd, CMSG_DATA(cmsg), sizeof(int)); } else { *fd = -1; } } LOGP(DE1D, LOGL_DEBUG, "rx pkt: %d %s\n", fd ? *fd : -2, msgb_hexdump(msgb)); return msgb; err: msgb_free(msgb); return NULL; } int osmo_e1dp_send(struct osmo_fd *ofd, struct msgb *msgb, int fd) { struct msghdr msg; struct iovec iov; char cmsgbuf[CMSG_SPACE(sizeof(int))]; int rc; memset(&msg, 0x00, sizeof(msg)); iov.iov_base = msgb->data; iov.iov_len = msgb_length(msgb); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; if (fd >= 0) { msg.msg_control = cmsgbuf; msg.msg_controllen = CMSG_LEN(sizeof(int)); struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); memmove(CMSG_DATA(cmsg), &fd, sizeof(int)); } rc = sendmsg(ofd->fd, &msg, 0); if (rc < 0) { LOGP(DE1D, LOGL_ERROR, "Failed to send packet.\n"); perror("tx"); } if (fd >= 0) close(fd); LOGP(DE1D, LOGL_DEBUG, "tx pkt: %d %s\n", msgb_length(msgb), msgb_hexdump(msgb)); return rc; }