Add interface for sending and receiving ESMC frames.
Ethernet Synchronization Messaging Channel (ESMC) requires
to operate on multicast raw L2 socket. This patch adds features
to open socket, send and receive ESMC frames.

Co-developed-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Signed-off-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Co-developed-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com>
---
 esmc_socket.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++
 esmc_socket.h |  53 ++++++++++++++++++++++++
 2 files changed, 164 insertions(+)
 create mode 100644 esmc_socket.c
 create mode 100644 esmc_socket.h

diff --git a/esmc_socket.c b/esmc_socket.c
new file mode 100644
index 000000000000..887b3c98f285
--- /dev/null
+++ b/esmc_socket.c
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/**
+ * @file synce_socket.c
+ * @brief Implements the ESMC socket.
+ * @note Copyright (C) 2022 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2, as published
+ * by the Free Software Foundation.
+ *
+ * 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 General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/if_ether.h>
+
+#include "sk.h"
+#include "print.h"
+#include "synce_msg.h"
+#include "synce_msg_private.h"
+#include "esmc_socket.h"
+
+int open_esmc_socket(const char *iface)
+{
+       unsigned char multicast_macaddr[MAC_LEN] = SYNCE_DEST_MACADDR;
+       struct sockaddr_ll addr;
+       struct packet_mreq mreq;
+       int fd, index, err;
+
+       fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 
htons(SYNCE_ETHERTYPE));
+       if (fd < 0) {
+               pr_err("socket failed: %m");
+               return -1;
+       }
+       index = sk_interface_index(fd, iface);
+       if (index < 0) {
+               goto no_option;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sll_ifindex = index;
+       addr.sll_family = AF_PACKET;
+       addr.sll_protocol = htons(SYNCE_ETHERTYPE);
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr))) {
+               pr_err("bind failed: %m");
+               goto no_option;
+       }
+       err = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface,
+                        strnlen(iface, IFNAMSIZ));
+       if (err) {
+               pr_err("setsockopt SO_BINDTODEVICE failed: %m");
+               goto no_option;
+       }
+
+       memset(&mreq, 0, sizeof(mreq));
+       mreq.mr_ifindex = index;
+       mreq.mr_type = PACKET_MR_MULTICAST;
+       mreq.mr_alen = MAC_LEN;
+       if (sizeof(mreq.mr_address) * sizeof(mreq.mr_address[0]) <
+           sizeof(multicast_macaddr) * sizeof(multicast_macaddr[0])) {
+               pr_err("setting multicast address failed");
+               goto no_option;
+       }
+       memset(mreq.mr_address, 0, sizeof(mreq.mr_address));
+       // we need to copy only 6 bytes to mreq.mr_address
+       memcpy(mreq.mr_address, multicast_macaddr, sizeof(multicast_macaddr));
+
+       err = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, 
sizeof(mreq));
+       if (err) {
+               pr_warning("setsockopt PACKET_MR_MULTICAST failed: %m");
+       }
+
+       return fd;
+
+no_option:
+       close(fd);
+
+       return -1;
+}
+
+int send_raw_esmc_frame(int socket, void *frame, int frame_len, int ifindex)
+{
+       struct sockaddr_ll saddrll;
+       int ret, frame_size;
+
+       memset(&saddrll, 0, sizeof(saddrll));
+       saddrll.sll_ifindex = ifindex;
+
+       frame_size = frame_len > ETH_ZLEN ? frame_len : ETH_ZLEN;
+       ret = sendto(socket, frame, frame_size, 0,
+                    (struct sockaddr *)&saddrll, sizeof(saddrll));
+       if (ret < 0) {
+               pr_err("%s failed: %m", __func__);
+               return errno;
+       }
+
+       return 0;
+}
+
+int recv_raw_esmc_frame(int socket, void *buff)
+{
+       return recv(socket, buff, ETH_DATA_LEN, 0);
+}
diff --git a/esmc_socket.h b/esmc_socket.h
new file mode 100644
index 000000000000..a496f7bd7690
--- /dev/null
+++ b/esmc_socket.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/**
+ * @file esmc_socket.h
+ * @brief Implements the ESMC socket.
+ * @note Copyright (C) 2022 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2, as published
+ * by the Free Software Foundation.
+ *
+ * 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 General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVE_ESMC_SOCKET_H
+#define HAVE_ESMC_SOCKET_H
+
+/**
+ * Creates a raw ESMC socket and binds it to given interface.
+ *
+ * This high level API creates raw socket and binds it to specified
+ * interface and binds it to ESMC L2 multicast address. Thanks to
+ * those binds we are able to receive frames only on specified interface.
+ *
+ * @param iface        A name of interface to bind to raw socket
+ * @return     A raw socket file descriptor, negative if error occurred
+ */
+int open_esmc_socket(const char *iface);
+
+/**
+ * Sends a raw ESMC frame on given interface.
+ *
+ * @param socket               A file descriptor of open raw ESMC socket
+ * @param frame                A pointer to raw ESMC frame buffer
+ * @param frame_len    A size of frame to be sent
+ * @return             Zero on success, non-zero if the sending failed
+ */
+int send_raw_esmc_frame(int socket, void *frame, int frame_len, int ifindex);
+
+/**
+ * Receives a raw ESMC frame on given interface.
+ *
+ * @param socket               A file descriptor of open raw ESMC socket
+ * @param buff         A pointer to raw ESMC frame buffer
+ * @return             Zero on success, non-zero if the reception failed
+ */
+int recv_raw_esmc_frame(int socket, void *buff);
+
+#endif
-- 
2.34.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to